一、JVM的内存组成结构
JVM内存结构由堆、栈、本地方法栈、方法区等部分组成,结构图如下:
1、堆
所有通过new创建的对象的内存都在堆中分配,其大小可通过-Xmx和-Xms来控制。堆被划分为新生代和旧生代,新生代又被进一步划分为Eden和Survivor由FromSpace和ToSpace组成,结构如下图:
新生代:新建的对象都是用新生代分配内存,Eden空间不足时,会把存活的对象转移到Survivor中,新生代大小可以由-Xmn来控制,也可以用-XX:SurvivorRadio来控制Eden和Survivor的比例。
旧生代:用于存放新生代经过多次垃圾回收(也即Minor GC)仍然存活的对象。
2、栈
每个线程执行每个方法的时候都会在栈中申请一个栈帧,每个栈帧包括局部变量区和操作数栈,用于存放此次方法调用过程中的临时变量、参数和中间结果。
3、本地方法栈
用于支持native方法的执行,存储了每个native方法调用的状态。
4、方法区
存放了要加载的类信息,静态变量,final类型的常量、属性和方法信息。JVM用持久代(或者叫永久代,PermanetGeneration)来存放方法区,可通过-XX:PermSize和-XX:MaxPermSize来指定最小值和最大值。在过去自定义类加载器还不是很常见的时候,类大多是static的,很少被卸载或收集,因此被称为“永久的(Permanent)”。同时,由于类Class是JVM实现的一部分,并不是由应用创建的,所以又被认为是“非堆(non-heap)”内存。在JDK1.8之前的HotSpot JVM,存放这些“永久的”区域叫做“永久代(Permanent Generation)”。永久代是一片连续的堆空间,在JVM启动之前通过在命令行设置参数-XX:MaxPermSize来设置永久代最大可分配的内存空间,默认是64M(64位JVM由于指针膨胀,默认是85M)。永久代的垃圾收集是和老年代(Old Generation)捆绑在一起的,因此无论谁满了,都会触发永久代和老年代的垃圾收集。不过,一个明显的问题是当JVM加载的类信息容量超过参数-XX:MaxPermSize设定的值时,应用将会报OOM的错误。永久代在JDK1.8中被完全的移除了。所以永久代的参数-XX:PermSize和-XX:MaxPermSize也被移除了。在JDK1.8中,class metadata(the virtual machines internal presentation of Java class),被存储在叫做Metaspace的native memory。一些新的flags被加入:
-XX:MetaspaceSize:class metadata的初始空间配额,以bytes为单位,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整;如果释放了大量的空间,就适当地降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSizes(如果设置了的话)时,就适当地提高该值。
-XX:MaxMetaspaceSize:可以为class metadata分配的最大空间。默认是没有限制的。
-XX:MInMetaspaceFreeRadio:在GC之后,最小的Metaspace剩余空间容量的百分比,减少为class metadata分配空间导致的垃圾收集。
-XX:MaxMetaspaceFreeRadio:在GC之后,最大的Metaspace剩余空间容量的百分比,减少为class metadata分配空间导致的垃圾收集。
默认情况下,class metadata的分配权受限于可用的native memory总量。可以使用MaxMetaspaceSize来限制可以为class metadata分配的最大内存。当class metadata的使用的内存达到MetaspaceSize(32位clientVM默认是16M)时就会对死亡的类加载器和类进行垃圾收集。设置MetaspaceSize为一个较高的值可以推迟垃圾收集的发生。
介绍完了JVM内存组成结构,下面我们再来看一下JVM垃圾回收机制。
二、Java中GC的基本算法
1、引用计数(reference counting)
原理:此对象有一个引用,则加1;删除一个引用,则减1。只用收集计数为0的对象。
缺点:1)无法处理循环引用的问题。如:对象A和B分别有字段b、a,令A.b=B和B.a=A,除此之外这2个对象再无任何引用,那实际上这两个对象已经不可能再被访问,但是引用计数算法却无法回收他们。2)引用计数的方法需要编译器的配合。编译器需要为此对象生成额外的代码。如赋值函数将此对象赋值给一个引用时,需要增加此对象的引用计数。还有就是,当一个引用变量的生命周期结束时,需要更新此对象的引用计数器。引用计数的方法由于存在显著的缺点,实际上并未被JVM所使用。
2、复制(copying)
原理:把内存空间划分为2个相等的区域,每次只使用一个区域。垃圾回收时,遍历当前使用区域,把正在使用的对象复制到另外一个区域。
优点:不会出现碎片问题。
缺点:1)暂停整个应用。2)需要2倍的内存空间。
3、标记-清扫(mark-and-sweep)
原理:对于“活”的对象,一定可以追溯到其存活在堆栈、静态存储区之中的引用。这个引用链条可能会穿过数个对象层次,算法基于有向图,采用深度优先搜索。第一阶段,从GC roots开始遍历所有的引用,对有活的对象进行标记;第二阶段,对堆进行遍历,把未标记的对象进行清除。
优点:解决了循环引用的问题。
缺点:1)暂停整个应用;2)会产生内存碎片;3)不管你这个对象是不是可达的,即是不是垃圾,都要在清除阶段检查一遍,非常耗时。sun前期版本就是用这个技术。
4、标记-压缩(mark-compact)
第一阶段,同标记-清扫,标记活的对象;第二阶段,将所有做了标记的活动对象整理到堆的底部。
优点:1)避免标记扫描的碎片问题;2)避免停止复制的空间问题。
5、分代(generational collecting)
原理:基于对象生命周期分析得出的垃圾回收算法。把对象分为年轻代、年老代、持久代,对不同的生命周期使用不同的算法(2-3方法中的一个即4自适应)进行回收。J2SE1.2以后使用此算法。JVM分别对新生代和旧生代采用不同的垃圾回收机制。
1)新生代GC(Minor GC):指发生在新生代的垃圾收集动作,因为Java对象大都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也比较快。新生代通常存活时间较短,因此基于Copying算法来进行回收,所谓Copying算法就是扫描出存活的对象,并复制到一块新的完全未使用的空间中,对应于新生代,就是在Eden和FromSpace或ToSpace之间copy。新生代采用空闲指针的方式来控制GC触发,指针保持最后一个分配的对象在新生代区间的位置,当有新的对象要分配内存时,用于检查空间是否足够,不够就触发GC。当连续分配对象时,对象会逐渐从Eden到Survivor,最后到旧生代。
2)旧生代GC(Major GC/Full GC):指发生在老年代的GC。旧生代与新生代不同,对象存活的时间比较长,比较稳定,因此采用标记(Mark)算法来进行回收,所谓标记就是扫描出存活的对象,然后再进行回收未被标记的对象,回收后对空出的空间要么进行合并,要么标记出来便于下次进行分配,总之就是要减少内存碎片带来的效率损耗。Major GC的速度一般会比Minor GC慢10倍以上。Think in Java中对Java GC的描述是这样的:“自适应、分代的、停止-复制、标记-扫描”式的垃圾回收器。
导致GC的情况如下:tenured被写满;perm被写满;System.gc()显示调用;上一次GC之后heap的各域分配策略动态变化。
相关推荐
Java中有多种垃圾回收器可供选择,包括Serial GC、Parallel GC、Concurrent Mark Sweep (CMS) GC 和 Garbage First (G1) GC等。每种GC都有其特点,适用于不同的应用场景。 #### Java集合框架 - **基础知识:** ...
10. **数据结构与算法**:虽然Java面试不一定涉及复杂算法,但基础的数据结构(如链表、树、图、队列、栈)的理解和常见算法(如排序、查找)的实现是必要的。 11. **Java新特性**:随着Java版本的更新,如Java 8的...
- 垃圾回收机制,如GC算法、新生代、老年代、内存溢出分析。 6. **Spring框架**: - Spring的核心组件,如IOC、AOP、MVC。 - Spring Boot的自动配置和微服务构建。 - Spring Cloud的分布式解决方案,如Eureka、...
在这个名为"java 扑克牌游戏"的项目中,我们可以深入探讨以下几个关键知识点: 1. **面向对象编程**:Java语言是面向对象的,因此在设计扑克牌游戏时,会涉及到类的创建,如`Card`(扑克牌)、`Deck`(牌堆)、`...
这包括如何调试代码、如何阅读和理解他人代码、如何设计和优化算法、如何处理异常以及如何进行单元测试等。 《Java面试宝典2018年最新版》这本书或PDF文档,将这些关键知识点以清晰、系统的方式呈现,是求职者准备...
- **GC原理**:了解垃圾收集器的工作机制,如Minor GC、Major GC和Full GC,以及垃圾回收算法,如标记-清除、复制、标记-整理和分代收集。 - **性能调优**:学习如何分析和调整JVM参数,如通过ThreadDump分析线程...
3. **创建许可证(数字签名)**:然后,使用`javakey`的`-gc`选项创建一个数字签名,这个签名将作为证书颁发给接收方。 4. **签名Java程序**:将生成的私钥用于签署Java程序(如MyApp.class),这可以通过Java的`...
理解GC的工作原理,如分代理论、GC算法(如标记-清除、复制、标记-整理、CMS、G1、ZGC等)、GC日志分析,对于优化应用程序性能至关重要。 4. **性能调优**:源码分析和工具使用常常是为了优化系统性能。这可能涉及...
面试中,面试官可能会询问你关于GC的工作原理,比如不同类型的垃圾收集器,如何调优GC参数,以及如何处理内存泄漏和长时间的垃圾收集暂停。 4. **多线程编程**(对应Day3 - Thread.txt): 多线程是并发执行任务的...
从 Java 7 开始,`switch` 支持 `String` 类型。 12. **List, Set, Map 是否继承自 Collection 接口?** - `List` 和 `Set` 继承自 `Collection` 接口,而 `Map` 是一个单独的接口,并不继承自 `Collection`。 13...
7. **垃圾回收**:学习Java内存管理,特别是垃圾收集器的工作原理,如新生代、老年代、CMS、G1等GC算法。 8. **字符串与字符编码**:深入理解String类的不可变性,以及各种字符编码如ASCII、Unicode、UTF-8的区别。...