jvm知识点

70 阅读8分钟

java运行时数据区

3bf3e1072319f070a898accdd6d5978a.jpeg www.51cto.com/article/784…

jvm 调优参数

  • -xmn:新生代大小
  • -xms:初始堆内存
  • -xms:堆最大内存
  • XX:newRedio: 新生代和老年代的比例
  • XX:survivorRedio: 新生代中edge和from/to的比例

如何判断对象是否是垃圾?

引用计数: 在对象中添加一个引用计数器,如果被引用计数器加 1,引用失效时计数器减 1,如果计数器为 0 则被标记为垃圾。原理简单,效率高,但是在 Java 中很少使用,因为存在对象间循环引用的问题,导致计数器无法清零。

可达性分析: 主流语言的内存管理都使用可达性分析判断对象是否存活。基本思路是通过一系列称为 GC Roots 的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程走过的路径称为引用链,如果某个对象到 GC Roots 没有任何引用链相连,则会被标记为垃圾。可作为 GC Roots 的对象包括虚拟机栈和本地方法栈中引用的对象、类静态属性引用的对象、常量引用的对象。

对象的访问方式有哪些?

Java 程序会通过栈上的 reference 引用操作堆对象,访问方式由虚拟机决定,主流访问方式主要有句柄和直接指针。

句柄:  堆会划分出一块内存作为句柄池,reference 中存储对象的句柄地址,句柄包含对象实例数据与类型数据的地址信息。优点是 reference 中存储的是稳定句柄地址,在 GC 过程中对象被移动时只会改变句柄的实例数据指针,而 reference 本身不需要修改。

直接指针:  堆中对象的内存布局就必须考虑如何放置访问类型数据的相关信息,reference 存储对象地址,如果只是访问对象本身就不需要多一次间接访问的开销。优点是速度更快,节省了一次指针定位的时间开销,HotSpot 主要使用直接指针进行对象访问。

如何判断对象是否是垃圾?

引用计数: 在对象中添加一个引用计数器,如果被引用计数器加 1,引用失效时计数器减 1,如果计数器为 0 则被标记为垃圾。原理简单,效率高,但是在 Java 中很少使用,因为存在对象间循环引用的问题,导致计数器无法清零。

可达性分析: 主流语言的内存管理都使用可达性分析判断对象是否存活。基本思路是通过一系列称为 GC Roots 的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程走过的路径称为引用链,如果某个对象到 GC Roots 没有任何引用链相连,则会被标记为垃圾。可作为 GC Roots 的对象包括虚拟机栈和本地方法栈中引用的对象、类静态属性引用的对象、常量引用的对象。

Java 的引用有哪些类型?

JDK1.2 后对引用进行了扩充,按强度分为四种:

强引用:  最常见的引用,例如 Object obj = new Object() 就属于强引用。只要对象有强引用指向且 GC Roots 可达,在内存回收时即使濒临内存耗尽也不会被回收。

软引用:  弱于强引用,描述非必需对象。在系统将发生内存溢出前,会把软引用关联的对象加入回收范围以获得更多内存空间。用来缓存服务器中间计算结果及不需要实时保存的用户行为等。

弱引用:  弱于软引用,描述非必需对象。弱引用关联的对象只能生存到下次 YGC 前,当垃圾收集器开始工作时无论当前内存是否足够都会回收只被弱引用关联的对象。由于 YGC 具有不确定性,因此弱引用何时被回收也不确定。

虚引用:  最弱的引用,定义完成后无法通过该引用获取对象。唯一目的就是为了能在对象被回收时收到一个系统通知。虚引用必须与引用队列联合使用,垃圾回收时如果出现虚引用,就会在回收对象前把这个虚引用加入引用队列。

有哪些 GC 算法?

标记-清除算法

分为标记和清除阶段,首先从每个 GC Roots 出发依次标记有引用关系的对象,最后清除没有标记的对象。

执行效率不稳定,如果堆包含大量对象且大部分需要回收,必须进行大量标记清除,导致效率随对象数量增长而降低。

存在内存空间碎片化问题,会产生大量不连续的内存碎片,导致以后需要分配大对象时容易触发 Full GC。

标记-复制算法

为了解决内存碎片问题,将可用内存按容量划分为大小相等的两块,每次只使用其中一块。当使用的这块空间用完了,就将存活对象复制到另一块,再把已使用过的内存空间一次清理掉。主要用于进行新生代。

实现简单、运行高效,解决了内存碎片问题。 代价是可用内存缩小为原来的一半,浪费空间。

HotSpot 把新生代划分为一块较大的 Eden 和两块较小的 Survivor,每次分配内存只使用 Eden 和其中一块 Survivor。垃圾收集时将 Eden 和 Survivor 中仍然存活的对象一次性复制到另一块 Survivor 上,然后直接清理掉 Eden 和已用过的那块 Survivor。HotSpot 默认Eden 和 Survivor 的大小比例是 8:1,即每次新生代中可用空间为整个新生代的 90%。

标记-整理算法

标记-复制算法在对象存活率高时要进行较多复制操作,效率低。如果不想浪费空间,就需要有额外空间分配担保,应对被使用内存中所有对象都存活的极端情况,所以老年代一般不使用此算法

老年代使用标记-整理算法,标记过程与标记-清除算法一样,但不直接清理可回收对象,而是让所有存活对象都向内存空间一端移动,然后清理掉边界以外的内存。

标记-清除与标记-整理的差异在于前者是一种非移动式算法而后者是移动式的。如果移动存活对象,尤其是在老年代这种每次回收都有大量对象存活的区域,是一种极为负重的操作,而且移动必须全程暂停用户线程。如果不移动对象就会导致空间碎片问题,只能依赖更复杂的内存分配器和访问器解决。

你知道哪些故障处理工具?

jps:虚拟机进程状况工具

功能和 ps 命令类似:可以列出正在运行的虚拟机进程,显示虚拟机执行主类名称以及这些进程的本地虚拟机唯一 ID(LVMID)。LVMID 与操作系统的进程 ID(PID)一致,使用 Windows 的任务管理器或 UNIX 的 ps 命令也可以查询到虚拟机进程的 LVMID,但如果同时启动了多个虚拟机进程,必须依赖 jps 命令。

jstat:虚拟机统计信息监视工具

用于监视虚拟机各种运行状态信息。可以显示本地或远程虚拟机进程中的类加载、内存、垃圾收集、即时编译器等运行时数据,在没有 GUI 界面的服务器上是运行期定位虚拟机性能问题的常用工具。

参数含义:S0 和 S1 表示两个 Survivor,E 表示新生代,O 表示老年代,YGC 表示 Young GC 次数,YGCT 表示 Young GC 耗时,FGC 表示 Full GC 次数,FGCT 表示 Full GC 耗时,GCT 表示 GC 总耗时。

jinfo:Java 配置信息工具

实时查看和调整虚拟机各项参数,使用 jps 的 -v 参数可以查看虚拟机启动时显式指定的参数,但如果想知道未显式指定的参数值只能使用 jinfo 的 -flag 查询。

jmap:Java 内存映像工具

用于生成堆转储快照,还可以查询 finalize 执行队列、Java 堆和方法区的详细信息,如空间使用率,当前使用的是哪种收集器等。和 jinfo 一样,部分功能在 Windows 受限,除了生成堆转储快照的 -dump 和查看每个类实例的 -histo 外,其余选项只能在 Linux 使用。

jhat:虚拟机堆转储快照分析工具

JDK 提供 jhat 与 jmap 搭配使用分析 jmap 生成的堆转储快照。jhat 内置了一个微型的 HTTP/Web 服务器,生成堆转储快照的分析结果后可以在浏览器查看。

jstack:Java 堆栈跟踪工具

用于生成虚拟机当前时刻的线程快照。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的目的通常是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间挂起等。线程出现停顿时通过 jstack 查看各个线程的调用堆栈,可以获知没有响应的线程在后台做什么或等什么资源。

类加载是什么? 什么是双亲委派

blog.csdn.net/u010257931/…