`
huoyanxueren
  • 浏览: 39778 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

虚拟机stack全分析

 
阅读更多

 

通过jps -lv 获取到本地的一个JVM实例进程。再通过jstack pid  > thread.txt ,把stack trace输出到thread.txt文件中。

2012-08-28 23:16:39

 

 

2012-08-28 23:16:39
Full thread dump OpenJDK Client VM (19.0-b09 mixed mode, sharing):

"Attach Listener" daemon prio=10 tid=0xb3da5400 nid=0x13ea waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Worker-15" prio=10 tid=0x09b7b400 nid=0x12f2 in Object.wait() [0xb30f9000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)
	- locked <0x6e5f87c0> (a org.eclipse.core.internal.jobs.WorkerPool)
	at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)

"Worker-12" prio=10 tid=0x09910c00 nid=0x12a0 in Object.wait() [0xb4026000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)
	- locked <0x6e5f87c0> (a org.eclipse.core.internal.jobs.WorkerPool)
	at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)
	at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)

.......省略

"Low Memory Detector" daemon prio=10 tid=0x097eb000 nid=0xa9f runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"CompilerThread0" daemon prio=10 tid=0x097e9000 nid=0xa9e waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x097e7400 nid=0xa9d runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=10 tid=0x097e4000 nid=0xa9c in Object.wait() [0xb4dd1000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:133)
	- locked <0x6e2e02f8> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:149)
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)

"Reference Handler" daemon prio=10 tid=0x097df400 nid=0xa9b in Object.wait() [0xb4e22000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:502)
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
	- locked <0x6e2e0098> (a java.lang.ref.Reference$Lock)

"main" prio=10 tid=0x097b0400 nid=0xa99 runnable [0xbf8b9000]
   java.lang.Thread.State: RUNNABLE
	at org.eclipse.swt.internal.gtk.OS.Call(Native Method)
	at org.eclipse.swt.widgets.Display.sleep(Display.java:4069)
	at org.eclipse.ui.application.WorkbenchAdvisor.eventLoopIdle(WorkbenchAdvisor.java:364)
	at org.eclipse.ui.internal.ide.application.IDEWorkbenchAdvisor.eventLoopIdle(IDEWorkbenchAdvisor.java:917)
	at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:2697)
	at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:2660)
	at org.eclipse.ui.internal.Workbench.access$4(Workbench.java:2494)
	at org.eclipse.ui.internal.Workbench$7.run(Workbench.java:674)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:667)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:149)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:123)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:344)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:179)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:616)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:622)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:577)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1410)

"VM Thread" prio=10 tid=0x097dd800 nid=0xa9a runnable 
"GC task thread#0 (ParallelGC)" prio=10 tid=0x08726800 nid=0x1e30 runnable

"GC task thread#1 (ParallelGC)" prio=10 tid=0x08727c00 nid=0x1e31 runnable

"VM Periodic Task Thread" prio=10 tid=0x097ed400 nid=0xaa0 waiting on condition 

JNI global references: 2131


上面的stack trace一共可以拆解成5个部分。

第一部分: Full thread dump identifier

 

2012-08-28 23:16:39
Full thread dump OpenJDK Client VM (19.0-b09 mixed mode, sharing):

 可以看到dump时间,虚拟机的信息。


第二部分: Java EE middleware, third party & custom application Threads

 

 

"Worker-15" prio=10 tid=0x09b7b400 nid=0x12f2 in Object.wait() [0xb30f9000]  
   java.lang.Thread.State: TIMED_WAITING (on object monitor)  
    at java.lang.Object.wait(Native Method)  
    at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)  
    - locked <0x6e5f87c0> (a org.eclipse.core.internal.jobs.WorkerPool)  
    at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)  
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:50)
 

 

 

此处是我们最为关心的地方,也是通过stack trace查找问题的地方,每个item的具体含义是

-Thread name: "Worker-15"

-线程优先级: prio=10

-java线程的identifier:tid=0x09b7b400

-native线程的identifier: nid=0x12f2

-线程的状态: in Object.wait()  java.lang.Thread.State: TIMED_WAITING (on object monitor)  

-线程栈起始地址:[0xb30f9000]  

 


Java线程和Native线程,也就是tid和nid的区别?

VM是加载并执行字节码的机器,这个处理不对应具体硬件,它完全由软件来实现。虚拟机并不是直接跑在宿主的cpu上,中间还隔着宿主的操作系统。

 

虚拟机的职责是:翻译字节码,把它翻译成一系列的动作(内存操作)和系统调用(比如输入输出)。举个例子:当在java里请求与某台远程机器建立socket连接时,java虚拟机本身是不能完成这一工作的(协议栈是在操作系统内实现的),所以它需要系统调用。要明白这个,还需要知道JRE和JVM的关系。JRE是JVM的环境,一个应用程序就是一个JVM实例。一个机器上一般同时只有一个JRE环境,但是可以同时有多个JVM实例。不同的操作系统和CPU架构有不同的JRE。JRE包含了最基本的类库,当然包括和操作系统打交道的Native库,比如windows下的dll文件,linux下的so文件。JVM实例解析字节码的成JVM中的指令集,再通过Native方法进行操作系统层面的系统调用。下面的图能比较清楚的说明问题。


 

 

JVM线程如何创建

当然是通过Native库的 native方法。JVM的线程最终是通过操作系统的线程来完成系统调用的。针对Java开发者来说,发号施令的是JVM 线程,具体干藏活累活的却是操作系统线程。不同操作系统上,JVM创建本地线程依赖的native库也不同。具体可参考下面的的文章。http://jackyhongvip.iteye.com/blog/1338610


JVM线程状态

 

状态有Runnable、Wait on condition、Waiting for monitor entry 和 in Object.wait()。

Runnable:不解释

Wait on condition:该状态出现在线程等待某个条件的发生。具体是什么原因,可以结合 stacktrace来分析。最常见的情况是线程在等待网络的读写。如果网络数据没准备好,线程就等待在那里。另外一种出现 Wait on condition的常见情况是该线程在 sleep,等待 sleep的时间到了时候,将被唤醒。

Waiting for monitor entry 和 in Object.wait():这两种情况在多线程的情况下经常出现。Java是通过Monitor来实现线程互斥和协作(有些把Monitor直译成锁,我认为不妥,不是还有Lock嘛)。具体Monitor的深入理解见 http://www.cnblogs.com/tomsheep/archive/2010/06/09/1754419.html

但是可以理解成Monitor是一个对象或者class所拥有的锁,每个对象和class有且仅有一个。见下图.


每个 Monitor在某个时刻,只能被一个线程拥有,该线程就是 “Active Thread”,而其它线程都是 “Waiting Thread”,分别在两个队列 “ Entry Set”和 “Wait Set”里面等候。

在 “ Entry Set”里面的线程都等待拿到Monitor,拿到了线程就成为了Runnable线程,否则就会一直处于处于 “waiting for monitor entry”。一段代码作为例子

 

 

public class MyThread implements Runnable{	

	 public void run() {  
         synchronized(this) {  
              for (int i = 0; i < 1; i--) {  
                   System.out.println(Thread.currentThread().getName() + " synchronized loop " + i);  
              }  
         }  
    }  
    public static void main(String[] args) {  
    	MyThread t1 = new MyThread();  
         Thread ta = new Thread(t1, "A");  
         Thread tb = new Thread(t1, "B");  
         ta.start();  
         tb.start();  
    } 

}

 

 

大家一看就知道,B线程肯定是“千年老二“,永远拿不到Monitor了。

对应的stack:

 

"B" prio=10 tid=0x0969a000 nid=0x11d6 waiting for monitor entry [0x8bb22000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.marshal.MyThread.run(MyThread.java:7)
	- waiting to lock <0x94757078> (a org.marshal.MyThread)
	at java.lang.Thread.run(Thread.java:636)

"A" prio=10 tid=0x09698800 nid=0x11d5 runnable [0x8bb73000]
   java.lang.Thread.State: RUNNABLE
	at java.io.FileOutputStream.writeBytes(Native Method)
	at java.io.FileOutputStream.write(FileOutputStream.java:297)
	at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
	at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
	- locked <0x947571b0> (a java.io.BufferedOutputStream)
	at java.io.PrintStream.write(PrintStream.java:449)
	- locked <0x94757190> (a java.io.PrintStream)
	at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:220)
	at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:290)
	at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:103)
	- locked <0x947572a0> (a java.io.OutputStreamWriter)
	at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
	at java.io.PrintStream.write(PrintStream.java:494)
	- locked <0x94757190> (a java.io.PrintStream)
	at java.io.PrintStream.print(PrintStream.java:636)
	at java.io.PrintStream.println(PrintStream.java:773)
	- locked <0x94757190> (a java.io.PrintStream)
	at org.marshal.MyThread.run(MyThread.java:8)
	- locked <0x94757078> (a org.marshal.MyThread)
	at java.lang.Thread.run(Thread.java:636)

   <0x94757078> 就是两个线程争夺的Monitor。

 

在 “Wait Set”里面的线程都如饥似渴地等待拿到Monitor。他们是怎么进入到“Wait Set”的呢?当一个线程拿到了Monitor,但是在其他资源没有到位的情况下,调用同步锁对象(一般是synchronized()内的对象)的 wait() 方法,放弃了 Monitor,它就进入到了 “Wait Set”队列。只有当其他线程通过notify() 或者 notifyAll(),释放了同步锁后,这个线程才会有机会重新去竞争Monitor。在stack中,它表现的状态是in Object.wait()。修改上面的代码public class WaitThread implements Runnable{ 

	 public void run() {  
        synchronized(this) { 
        	try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}            
        }  
   }  
   public static void main(String[] args) {  
	    WaitThread t1 = new WaitThread();  
        Thread ta = new Thread(t1, "A");  
        Thread tb = new Thread(t1, "B");  
        ta.start();  
        tb.start();          
   } 

}

 对应的stack:

 

"B" prio=10 tid=0x08173000 nid=0x1304 in Object.wait() [0x8baf2000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0xa9cb50e0> (a org.marshal.WaitThread)
	at java.lang.Object.wait(Object.java:502)
	at org.marshal.WaitThread.run(WaitThread.java:8)
	- locked <0xa9cb50e0> (a org.marshal.WaitThread)
	at java.lang.Thread.run(Thread.java:636)

"A" prio=10 tid=0x08171c00 nid=0x1303 in Object.wait() [0x8bb43000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0xa9cb50e0> (a org.marshal.WaitThread)
	at java.lang.Object.wait(Object.java:502)
	at org.marshal.WaitThread.run(WaitThread.java:8)
	- locked <0xa9cb50e0> (a org.marshal.WaitThread)
	at java.lang.Thread.run(Thread.java:636)

 A和B线程都进入了”wait set“。B线程也拿到过这个Monitor,因为A线程释放过了,这也验证上面的话,他们都在等待得而复失的<0xa9cb50e0>。

 

基于我们经常讨论到的死锁问题,构造一段代码如下

 

public class DeadThread implements Runnable{
	
	private Object monitor_A = new Object();
	
	private Object monitor_B = new Object();
	
	public void  method_A(){
		 synchronized(monitor_A) { 
	    	   synchronized(monitor_B) { 
	               System.out.println(Thread.currentThread().getName()+" invoke method A");
	           }                
	       }  		
	}
	
	public void  method_B(){
		 synchronized(monitor_B) { 
	    	   synchronized(monitor_A) { 
	    		   System.out.println(Thread.currentThread().getName()+" invoke method B");
	           }                
	       }  		
	}	

	public void run() {		
		for(int i=0;i<1;i--){			 
			method_A();			 
			method_B(); 			 		 
		}		     
	}
	 
  public static void main(String[] args) {  
	  DeadThread t1 = new DeadThread();  
       Thread ta = new Thread(t1, "A");  
       Thread tb = new Thread(t1, "B");  
  
       ta.start();  
       tb.start(); 
  } 
}

  对应的stack:

 

"B" prio=10 tid=0x0898d000 nid=0x269a waiting for monitor entry [0x8baa2000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.marshal.DeadThread.method_A(DeadThread.java:11)
	- waiting to lock <0xaa4d6f88> (a java.lang.Object)
	- locked <0xaa4d6f80> (a java.lang.Object)
	at org.marshal.DeadThread.run(DeadThread.java:28)
	at java.lang.Thread.run(Thread.java:636)

"A" prio=10 tid=0x0898b800 nid=0x2699 waiting for monitor entry [0x8baf3000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.marshal.DeadThread.method_B(DeadThread.java:19)
	- waiting to lock <0xaa4d6f80> (a java.lang.Object)
	- locked <0xaa4d6f88> (a java.lang.Object)
	at org.marshal.DeadThread.run(DeadThread.java:29)
	at java.lang.Thread.run(Thread.java:636)

 同时注意到,在stack trace尾部信息

 

Found one Java-level deadlock:
=============================
"B":
  waiting to lock monitor 0x089615d8 (object 0xaa4d6f88, a java.lang.Object),
  which is held by "A"
"A":
  waiting to lock monitor 0x08962258 (object 0xaa4d6f80, a java.lang.Object),
  which is held by "B"

Java stack information for the threads listed above:
===================================================
"B":
	at org.marshal.DeadThread.method_A(DeadThread.java:11)
	- waiting to lock <0xaa4d6f88> (a java.lang.Object)
	- locked <0xaa4d6f80> (a java.lang.Object)
	at org.marshal.DeadThread.run(DeadThread.java:28)
	at java.lang.Thread.run(Thread.java:636)
"A":
	at org.marshal.DeadThread.method_B(DeadThread.java:19)
	- waiting to lock <0xaa4d6f80> (a java.lang.Object)
	- locked <0xaa4d6f88> (a java.lang.Object)
	at org.marshal.DeadThread.run(DeadThread.java:29)
	at java.lang.Thread.run(Thread.java:636)

Found 1 deadlock.

  stack中直接报告了Java级别的死锁,够智能吧。


第三部分:HotSpot VM Thread

 

"Low Memory Detector" daemon prio=10 tid=0x097eb000 nid=0xa9f runnable [0x00000000]  
   java.lang.Thread.State: RUNNABLE  
  
"CompilerThread0" daemon prio=10 tid=0x097e9000 nid=0xa9e waiting on condition [0x00000000]  
   java.lang.Thread.State: RUNNABLE 
 

JVM管理的内部线程,这些内部线程都是来执行native操作的,可以不必太关注。


第四部分: HotSpot GC Thread

 

"GC task thread#0 (ParallelGC)" prio=10 tid=0x08726800 nid=0x1e30 runnable

"GC task thread#1 (ParallelGC)" prio=10 tid=0x08727c00 nid=0x1e31 runnable

  当虚拟机打开了parallel GC,这些线程就会定期地GC清理。


第五部分:JNI global references count

 

JNI global references: 2131

 JNI (Java Native Interface)全局引用也是受垃圾回收器管理。它的作用是防止回收到那些在native代码上还是被引用的,但是在java代码中却没有存活必要的引用。对于防止因为应用代码中直接使用native库或者第三方的一些监控工具的内存泄漏有非常大的帮助。

 

 

 

参考文献:

http://peiliping.ixiezi.com/2012/04/15/jvm-jstack%E7%94%A8%E6%B3%95/

http://www.cnblogs.com/tomsheep/archive/2010/06/09/1754419.html

http://www.javacodegeeks.com/2012/03/jvm-how-to-analyze-thread-dump.html

http://blog.csdn.net/fenglibing/article/details/6411940

 

  • 大小: 9.9 KB
  • 大小: 9.1 KB
分享到:
评论
2 楼 Bruce_Tender 2018-10-29  
   非常感谢楼主分享
1 楼 carlosfu 2015-12-19  
非常好,收获很大,很赞。

相关推荐

    Java虚拟机实现原理分析.pdf

    在JVM内部,内存管理是一个重要的组成部分,涉及到堆(heap)和栈(stack)等多个内存区域。JVM负责分配和回收这些内存区域,以确保程序运行时的效率和稳定性。Java的内存管理机制包括垃圾回收(Garbage Collection,...

    javase8虚拟机结构

    通过对Java SE8虚拟机结构的分析,我们可以看出,Java虚拟机的设计充分考虑了多线程环境下的安全性和灵活性,同时通过合理划分内存区域,有效地支持了Java程序的高效运行。理解这些概念对于深入学习Java编程、优化...

    java 虚拟机 内存和栈 分析工具 ha456.rar

    本篇文章将深入探讨Java虚拟机的内存模型、栈空间以及相关的分析工具。 首先,我们来了解Java的内存模型。Java内存主要分为堆(Heap)、栈(Stack)、方法区(Method Area)、程序计数器(PC Register)和本地方法...

    java虚拟机运行时数据区分析

    Java虚拟机运行时数据区分析 Java虚拟机(JVM)是一种抽象的计算机,它提供了一个运行Java字节码的环境。JVM将Java源代码编译为字节码,并在运行时执行这些字节码。为了更好地理解JVM的工作原理,我们需要了解JVM的...

    深入java虚拟机源码

    JVM的动态编译是提升性能的关键,本章会介绍HotSpot虚拟机的编译策略,如OSR(On-Stack Replacement)和逃逸分析,以及如何通过-XX选项调整编译参数。 6. **第10章:多线程与并发** 在Java中,多线程编程是常见...

    Themida v1.8.0.0 Demo虚拟机分析(Part1-Part8) by softworm

    1. **VM Stack**:虚拟机使用的栈空间,大小为8KB。 2. **VM2-Bytes-OpcodeTable1**:一个地址表,用于存储指向其他表的指针。 3. **VM2-Bytes-OpcodeTable2**:Handler地址表,每三个地址构成一组,由前一个表中的...

    Java虚拟机简介

    #### 五、对比分析 为了更好地理解Java虚拟机的工作原理,可以将其与传统的C++程序进行对比: - **源程序**:Java源代码与C++源代码类似,都是高级语言的文本文件。 - **编译产物**:Java编译后的字节码与C++编译...

    虚拟机内存模型

    5. **本地方法栈(Native Method Stack)**:与虚拟机栈类似,但专为Java Native Interface (JNI)调用的本地方法服务。 了解了基本结构后,我们来看看相关的工具。在Java中,`jmap`和`jvisualvm`是两个常用的内存...

    深入理解jvm虚拟机

    主要包括方法区(Method Area)、堆(Heap)、Java栈(Java Stack)、本地方法栈(Native Method Stack)、程序计数器(Program Counter)五个部分。 4. 垃圾回收机制:JVM中的垃圾回收主要是针对堆区进行的。垃圾...

    Java虚拟机讲解笔记.docx

    - **JProfiler**: 第三方高级监控工具,提供了更深入的性能分析功能。 #### 七、虚拟机网络模式 - **桥接模式**: 使虚拟机能够像真实计算机一样访问网络。 - **仅主机模式**: 虚拟机只能访问宿主机及其内部网络,...

    Java运行原理与Java虚拟机.pdf

    3. **数据流分析**:字节码验证器会进行数据流分析,确保所有变量在使用前已经被正确初始化。 4. **访问控制**:JVM提供了严格的访问控制机制,确保只有经过授权的代码才能访问敏感资源。 5. **代码签名**:通过...

    Java虚拟机分析

    总之,Java虚拟机分析涉及到的知识点非常广泛,包括其架构组成、运行机制、实现方法和性能优化等。通过深入学习和实践,不仅可以加深对Java平台的理解,还能为开发高效、跨平台的Java应用打下坚实的基础。

    Java虚拟机

    4. **虚拟机栈(Virtual Machine Stack)** - 虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。 5. **本地方法栈...

    Java虚拟机性能参数调优指导书

    JVM在运行时会创建多个区域,如堆内存(Heap)、栈内存(Stack)、方法区(Method Area)等,每个区域都有其特定的作用。堆内存用于存储对象实例,栈内存则用于存储方法调用的信息。JVM通过解释器执行字节码,并在...

    深入理解Java虚拟机笔记(带目录).docx

    * 可达性分析法(Reachability Analysis):通过判断对象是否可以被 GC Roots 节点所达来判断对象是否死亡。 * finalize() 方法:通过对象的 finalize() 方法来判断对象是否死亡。 引用的 4 中情况 在 Java 中,...

    java虚拟机JVM详解ppt

    ##### 4.3 Java虚拟机栈(Java Virtual Machine Stack) Java虚拟机栈是线程私有的,用于存储方法执行的局部变量表、操作数栈、动态链接等信息。当线程请求的栈深度超过JVM允许的深度时,会抛出`StackOverflowError`...

    30+个视频+深入理解Java虚拟机(jvm优化+内存模型+虚拟机原理)

    使用`-XX:+PrintGC`打印GC日志以便于分析问题等。 4. **减少对象创建**: 对象创建是导致年轻代频繁GC的主要原因之一。可以通过缓存对象、复用对象等方式降低对象创建频率。 5. **避免内存泄漏**: 定期检查代码中...

Global site tag (gtag.js) - Google Analytics