java经过这么多年的发展,已经成为相当成熟的技术,特别是在内存的动态分配与内存回收技术已经相当成熟,一切看起来都是如此的美妙和谐。那我们为什么还要了解GC和内存分配呢?这个我想不用多说大家都应该明白,正是java的这种自动化,这个对大多数程序员的黑盒,导致排查各种内存溢出和内存泄露问题,甚至成为系统达到高并发的瓶颈。
当我们的程序在运行的过程中,程序计数器、虚拟机栈、本地方法栈都随线程而生,随线程而死;栈中的栈帧随着方法的进入退出有条不紊的进栈出栈,每一帧的内存大小基本在类结构确定下来就已知了,虽然栈帧分配多少内存会被JIT编译器进行一些优化,但是大体我们可以认为是编译器可知的。因此这些区域不需要过多考虑内存的回收问题,因为方法结束,内存就自动回收了,我们关注的是java的堆的垃圾回收。
我们在分析堆的垃圾回收之前,首先要弄清除哪些对象是应该被回收的,也就是说对象的生死怎么判断。目前我所知道的就两种算法来判断对象的存活,第一种是引用计数算法第二种是根搜索算法。引用计数算法,就是每个对象有一个引用计数器,每当有一个地方引用了该对象,计数器就加1;当引用失效时,计数器就减1;只有计数器为0的对象才可以被回收。这种算法实现方式很简单,效率也很高。这个算法在python和微软的COM中广泛使用,但是java却没有使用该算法,原因是它很难解决对象之间的相互引用问题。根搜索算法(GC Roots Tracing)被使用在java和C#中,这个算法就是从根节点开始向下搜索,搜索的路径就被成为引用连,当一个对象到GC Roots没有任何引用链可达时,就表明该对象是可以回收的了。在java中,可以作为GC Roots的对象有:1.虚拟机栈中引用的对象2.方法区中类静态属性引用的对象3.方法区中常量引用的对象4.本地方法栈JNI中引用的对象。但是并不是所有在根搜素算法中不可达的对象,都会被回收。一个对象真正的要被回收,至少要经历两次标记过程。如果对象在进行根搜索后发现没有与GC Roots相连接的引用链,那么它会被第一次标记并且进行一次筛选,筛选的条件是对象是否有必要执行finalize()方法。当对象没有重写finalize()方法,或者该方法已经被虚拟机调用过,虚拟机都认为没有必要执行。没有必要执行finalize方法的对象将会被放到一个队列中,这时虚拟机会在队列中进行第二次标记,如果还是没有到GC Roots可达引用链,那么它就会被回收。
我们已经讲了堆中对象是否存活的判定方法,下面我们得说说例外一个运行时数据区域:方法区或者叫做永久代。在堆中,特别是新生代,一次YGC就可以回收70%-95%的空间,而永久代的效率就低多了,很多人甚至认为方法区是没有垃圾回收。永久代回收的东西分为两种:无用的常量和无用的类。常量的回收很简单,比如一个String类型的数据“YY”,如果没有任何用到这个常量,如果这个时候发生内存回收,并且需要回收,该常量就会被回收。但是无用的类的判断就比较复杂了,条件有如下三个:1.该类的对象全部都被回收,堆中没有任何实例。2.加载该类的ClassLoader已经被回收。3.该类对应的Class对象没有被引用,没有地方通过反射来访问该类。当且仅当这三个条件满足,这个对象才可以被回收,但是不一定被回收,跟对象不一样。可以通过-Xnoclassgc进行控制,还可以通过-verbose:class和-XX:+TraceClassLoading、-XX:+TraceClassUnLoading查看类的加载和卸载信息。-verbose:class和-XX:+TraceClassLoading可以在product版的虚拟机中使用,但是-XX:TraceClassLoading参数需要fastdebug版的虚拟机支持。说了这多,其实在java的发展规划中,方法区也许会被Native Memory所代替。
分享到:
相关推荐
1. **JVM参数设置**:根据应用需求,设置合适的JVM启动参数,如堆大小(`-Xms`和`-Xmx`)、新生代与老年代的比例(`-XX:NewRatio`)、Eden区与Survivor区的比例(`-XX:SurvivorRatio`)、GC日志输出(`-XX:+...
1. **理解JVM内存结构**:Java内存主要分为堆内存(Heap)和非堆内存(Non-Heap),其中堆内存又分为新生代(Young Generation)、老年代(Tenured Generation或Old Generation)和持久代(Permanent Generation或...
GC-powerstation 9.1.2可能提供了更高效的垃圾回收算法、更好的性能监控、更精细的调优选项,或者对特定JVM(Java虚拟机)版本的支持。 PowerPlatform_oldEnglish这个文件名可能指的是该版本的文档或资源库,其中...
1. **JVM架构** - 类装载器:负责加载类文件到JVM中,分为引导类加载器、扩展类加载器和应用类加载器。 - 运行时数据区:包括方法区、堆、栈、本地方法栈和程序计数器。 - 执行引擎:解释执行字节码或通过即时...
深入java虚拟机光盘资源jvm-gc-logs-analyzer 这个项目是一个 Java 虚拟机和垃圾收集器日志分析器。 它专用于 JVM 11 及更高版本(JVM 8 支持正在开发中)。 日志必须采用适当的格式和适当的装饰器,检查最后部分的...
1、java虚拟机的基本介绍。 2、字节码的执行 3、常用的jvm参数配置 4、算法和种类 5、gc参数配置 6、类加载器 7、性能监控工具 8、jvm堆栈分析
1. `-Xms`: 这个参数用于设置JVM启动时初始的堆内存大小。默认情况下,JVM会从小到大动态地调整堆空间,但设置`-Xms`可以确保程序启动时就分配足够的内存,避免频繁的内存扩展操作,从而提高性能。例如,`-Xms256m`...
对gc日志进行统计分析,使用命令:java -jar gcviewer-1.3x.jar gc.log summary.csv [chart.png] [-t PLAIN|CSV|CSV_TS|SIMPLE|SUMMARY]
本文档可以作为学习JVM GC的工具书所使用,对于想深入学习JVM GC原理的同学,这一本书就足够了。因为本文档是作者花费数月时间,查阅GC相关的国内外众多资料并加以思路清晰的条目化而形成。因为篇幅所限,可能有部分...
1. JVM结构: - 类装载器(ClassLoader):负责加载类文件到JVM,包括Bootstrap ClassLoader(引导类加载器)、Extension ClassLoader(扩展类加载器)和AppClass ClassLoader(应用程序类加载器)。 - 运行时数据...
"jvm-full-gc.zip"这个压缩包很可能包含了关于JVM全GC(Full GC)的相关示例和资料,用于帮助理解JVM的内存管理和垃圾回收机制。 全GC(Full GC)是JVM进行垃圾回收的一种模式,主要涉及堆内存(包括年轻代和老年代...
- 如果系统花费在GC上的时间为1%,当系统跨越32个处理器时,系统的吞吐量将减少超过20%。 - 如果系统花费在GC上的时间为10%,当系统跨越32个处理器时,系统的吞吐量将减少高达75%。 **3.2 性能测量** - **Pause*...
总结来说,"jvm-int-gc-benchmark"项目旨在通过对JVM内部垃圾收集的基准测试,深入了解不同GC策略的性能特性。通过这种方式,开发者能够优化Java应用的内存管理,减少不必要的性能损耗,提升应用的整体性能。在实践...
1. **类加载器(ClassLoader)**:负责查找和加载类文件到JVM。它遵循双亲委托模型,确保类的唯一性。 2. **运行时数据区(Runtime Data Area)**:包括堆内存、方法区、虚拟机栈、本地方法栈和程序计数器。堆内存...
jvmgc过程介绍(jpg)
1. **JVM结构与工作原理**: - 类加载器:加载、验证、准备、解析和初始化类。 - 运行数据区:包括堆、方法区、虚拟机栈、本地方法栈和程序计数器。 - 堆内存:存储对象实例,分为新生代和老年代。 - 方法区:...
在JVM中,垃圾回收(GC)是自动管理内存的关键技术,其目的是回收不再使用的对象所占用的内存空间,以避免内存泄漏和提升系统性能。 首先,JVM内存分配策略主要涉及对象如何在堆内存的不同区域进行分配。对象在...
4. **垃圾收集(GC)**:Java的自动内存管理主要依赖于GC,它负责回收不再使用的对象所占用的内存。垃圾收集有多种算法,如引用计数法、标记-清除、复制、标记-整理和分代收集等。其中,引用计数法简单但难以处理...
在"JVM01-课程介绍1"中,我们将探讨一系列关于JVM的重要知识点,旨在帮助初中高级Java开发工程师和运维工程师提升技能,同时也适合对JVM技术感兴趣的师生学习。 首先,课程会从环境准备与相关设置开始,包括安装JDK...
3. 垃圾回收:Rust的内存管理机制与JVM的垃圾回收有异曲同工之妙,但需要自定义实现GC策略,如引用计数或标记-清除算法。 4. 执行引擎:使用Rust的迭代器和控制流结构实现字节码的解释执行。 五、实践与挑战 在...