The VA virtual machine provides a set of interfaces for debugging (jvmdi) and monitoring (jvmpi). After Java 5, it is unified as jvmti:
Http://docs.oracle.com/javase/1.5.0/docs/guide/jvmti.
Jvmdi is divided into three parts: jvmdi, jdwp, and jdi.
Http://docs.oracle.com/javase/1.4.2/docs/guide/jpda/architecture.html
This article briefly introduces how to use jdi to monitor program running.
Assume that there is a simple program:
Java code
- Package test;
- Public class test {
- Public static void main (string [] ARGs ){
- New thread (){
- @ Override
- Public void run (){
- Test test = new test ();
- While (true ){
- Try {
- Sleep (5000 );
- } Catch (interruptedexception e ){
- E. printstacktrace ();
- }
- Test. printhello ();
- }
- }
- }. Start ();
- }
- Protected void printhello (){
- System. Out. println ("hello ");
- }
- }
In the program, the printhello () method is executed once every five seconds.
If you want to notify you every time printhell () is executed, what do you do without modifying the code? No way, right?
Let's take a look at the definition of jdi:
Java code
- Jdi-Java debug Interface
- Defines a high-level Java language interface which tool developers can easily use to write remote debugger applications.
So first, we start the test class in the form of remote debugging:
Java code
- Java-xdebug-agentlib: jdwp = transport = dt_socket, Server = Y, suspend = N, address = 8800-CP. Test. Test
Generally, the test class is debugged through socket transmission. The connection port for debugging is 8800, and the connection process is not suspended.
The following output is displayed after a volume is started:
Java code
- Listening for transport dt_socket at address: 8800
- Hello
- Hello
- Hello
In this way, the server is ready for debugging. The following is the write listener. The jdi interface provided by JDK is used here. To use this interface, we need to include tools. jar and other packages under JDK in the class path, which can be found under the <JDK>/lib directory.
1. Get the connector Java code
- Virtualmachinemanager vmm = Bootstrap. virtualmachinemanager ();
- List <attachingconnector> connectors = vmm. attachingconnectors ();
- Socketattachingconnector sac = NULL;
- For (attachingconnector AC: connectors ){
- If (AC instanceof socketattachingconnector ){
- SAC = (socketattachingconnector) AC;
- Break;
- }
- }
- If (SAC = NULL ){
- System. Out. println ("jdi error ");
- Return;
- }
2. Connect to the remote virtual machine Java code
- Map arguments = sac. defaultarguments ();
- Connector. Argument hostarg = (connector. argument) arguments. Get (host );
- Connector. Argument portarg = (connector. argument) arguments. Get (port );
- Hostarg. setvalue ("127.0.0.1 ");
- Portarg. setvalue (string. valueof (8800 ));
- Vm = sac. Attach (arguments );
3. Get the Java code of the classes and methods to be concerned
- List <referencetype> classesbyname = VM. classesbyname ("Test. Test ");
- If (classesbyname = NULL | classesbyname. Size () = 0 ){
- System. Out. println ("no class found ");
- Return;
- }
- Referencetype RT = classesbyname. Get (0 );
- List <method> methodsbyname = Rt. methodsbyname ("printhello ");
- If (methodsbyname = NULL | methodsbyname. Size () = 0 ){
- System. Out. println ("No Method Found ");
- Return;
- }
- Method method = methodsbyname. Get (0 );
4. Register and listen to Java code
- VM. setdebugtracemode (virtualmachine. trace_events );
- VM. Resume ();
- Eventrequestmanager erm = VM. eventrequestmanager ();
- Methodentryrequest = Erm. createmethodentryrequest ();
- Methodentryrequest. addclassfilter (RT );
- Methodentryrequest. setsuspendpolicy (eventrequest. suspend_none );
- Methodentryrequest. Enable ();
- Breakpointrequest = Erm
- . Createbreakpointrequest (method. Location ());
- Breakpointrequest. setsuspendpolicy (eventrequest. suspend_event_thread );
- Breakpointrequest. Enable ();
- Eventloop ();
Listen to each method entry, register a breakpoint on the method, and send a notification.
Iv. Java code for implementing eventloop ()
- Private Static void eventloop () throws exception {
- Eventqueue = VM. eventqueue ();
- While (true ){
- If (vmexit = true ){
- Break;
- }
- Eventset = eventqueue. Remove ();
- Eventiterator = eventset. eventiterator ();
- While (eventiterator. hasnext ()){
- Event event = (event) eventiterator. Next ();
- Execute (event );
- }
- }
- }
- Private Static void execute (event) throws exception {
- If (event instanceof vmstartevent ){
- System. Out. println ("VM started ");
- Eventset. Resume ();
- } Else if (event instanceof breakpointevent ){
- System. Out
- . Println ("reach method printhello of Test. Test ");
- Eventset. Resume ();
- } Else if (event instanceof methodentryevent ){
- Methodentryevent mee = (methodentryevent) event;
- Method method = Mee. Method ();
- System. Out. println (method. Name () + "was entered! ");
- Eventset. Resume ();
- } Else if (event instanceof vmdisconnectevent ){
- Vmexit = true;
- } Else {
- Eventset. Resume ();
- }
- }
Finally, let's look at the output:
Java code
- [Jdi: eventset: suspend_event_thread]
- [Jdi: Event: MethodEntryEvent@test.Test: 23 in thread-0]
- [Jdi: Event: BreakpointEvent@test.Test: 23 in thread-0]
- Printhello was entered!
- Reach method printhello of Test. Test
- [Jdi: eventset: suspend_event_thread]
- Printhello was entered!
- [Jdi: Event: MethodEntryEvent@test.Test: 23 in thread-0]
- [Jdi: Event: BreakpointEvent@test.Test: 23 in thread-0]
- Reach method printhello of Test. Test