天问的私人面试宝典02 JVM

本文详细探讨了JVM的基本组成结构,包括主内存、工作内存、PC Register、JVM栈、本地方法栈、堆、方法区、运行时常量池和直接内存。重点讲解了Java内存模型(JMM)、垃圾回收机制、分代垃圾回收和常见垃圾回收器。此外,还涉及了内存溢出处理和调优技巧。
摘要由CSDN通过智能技术生成

JVM组成结构

JVM结构

区别Java内存模型JMM   Java Memory Model

Java内存模型是一套规范,描述了Java程序中的各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量的底层细节。

1.主内存:主内存是所有线程共享的,都能访问的,所有的共享变量都存储于主内存。

2.工作内存:每一个线程有自己的工作内存,工作内存只存储该线程对共享变量的副本,线程对变量的所有操作都必须在工作内存中完成,而不能直接读写主内存中的变量,不同线程之间也不能访问对方工作内存中的变量。

JMM的作用

        JMM是一套在多线程读写共享数据时,对共享数据的可见性、原子性、有序性的规则和保障。通过关键字synchronized 和 volatail。

PC Register程序计数器

记住下一条JVM指令的执行地址,通过寄存器来实现。

特点:线程私有;

          不会存在内存溢出。

虚拟机栈 JVM Stacks

栈是线程运行时需要的内存空间

栈帧:一个栈帧对应一次方法的调用,每个方法运行时需要的内存。

特点:先进后出

垃圾回收不涉及栈内存

栈内存越大,线程数越少,反而影响效率   500M/2M   500M/1M

方法内的局部变量是否线程安全?

        不会有线程安全问题,若是有static修饰,或者逃离了方法的作用范围(return),则需要考虑线程安全问题。

栈内存溢出

        1.栈帧过多会导致内存溢出,如递归且无终止条件,只进不出

        2..栈内存过大

溢出时报错:StacksOverFlowError

本地方法栈 Native Method Stacks

给本地方法运行提供运行空间

堆 Heap

通过new关键字,创建对象都会使用堆内存

特点:

        它是线程共享的,堆中对象都需要考虑线程安全的问题

        有垃圾回收机制

堆内存溢出:没使用了会回收,倘若一直在使用且增加,则会溢出

堆内存诊断工具:

        1.jps      查看当前系统中有哪些Java进程

        2.jmap工具    查看堆内存占用情况    jmap -heap 进程ID

        3.jconsole    也能检测死锁,图像化界面,更直观

        4.jvisualVM   若内存回收后,占用仍然很高 ,直观的查看内存情况

方法区  MethodArea

定义:所有Java虚拟机共享的区域,存储了跟类结构相关的信息,包括成员变量,方法数据、成员方法、构造方法等。

方法区在虚拟机启动时创建,逻辑上属于堆的一部分。

方法区内存溢出:

类加载器可以用来加载类的二进制字节码

1.8以前会导致永久代内存溢出

1.8以前会导致元空间内存溢出

运行时常量池

反编译:javap - v  类名.class

常量池就是一张表,虚拟机指令根据这张表找到要执行的类名、方法名、参数类型、字面量等信息

运行时常量池,常量池是*.class文件中的,当该类被加载,它的常量池信息就会放入运行时常量池,并把里面的符号地址变为真实地址。

StringTable 串池

String s1="a";

String s2="b";

String s3="ab";     //String ab

String s4=s1 +s2; //底层为  new StringBuilder().append("a").append("b").toString()     

                                    即   new  String("ab")                     所以s3  == s4  为false

String s5 ="a" + " b"  // String ab   javac 在编译器的优化,结果在编译期间确定为ab,s3 == s5  true

intern()方法:1.8将这个字符串对象尝试放入串池,如果有则不会放入,没有则放入。

直接内存DirectMemory

通过 ByteBuffer.allocateDirect(_1Gb)  分配一块直接内存,该区域java代码可以直接访问,系统也可以访问。

常用于NIO操作,用于数据缓冲区;

分配回收成本较高,单读写性能高(比IO快很多);

不受JVM内存回收管理。

allocateDirect 内部有个 DirectByteBuffer 该方法内又调用了allocateMemory、setMemory。

直接内存的分配、回收原理:

        分配和释放 是通过unsafe 来分配和释放(调用unsafe.freememory)的,不是垃圾回收。

        ByteBuffer的实现类内部,使用了 Cleaner(虚引用)来监测ByteBuffer对象,一旦ByteBuffer对象被垃圾回收,呢么就会由ReferenceHandler线程通过Cleaner的clean的方法调用freeMemory来释放直接内存。

垃圾回收

1.如何判断对象可以回收

        1.1引用计数法  引用一次+1,为0时表示无人引用,此时可回收。弊端:循环引用,A引用B,B引用A。

        1.2可达性分析算法   首先确定一系列根对象 GC Root(肯定不会当成垃圾的对象),垃圾回收前对堆内存中的对象进行一遍扫描,若被根对象直接或间接的引用之不能被回收,反之可以回收。可通过MAT工具来查看哪些GC Root。

        1.3四种引用     强引用;软引用、弱引用、虚引用、终结器引用

        强引用:只有GC Root对象都不通过强引用引用该对象才能被回收。

        软引用:未被强引用引用。垃圾回收并且内存不足时,弱引用的对象被回收。

                       可以配合引用队列释放软引用本身。

        弱引用:只要垃圾回收,不管内存是否足够,都会被回收。

                       可以配合引用队列释放软引用本身。

        虚引用:必须配合引用队列来使用。主要配合ByteBuffer使用,被引用对象回收时会将虚引                          用引用入队,由Reference Handler线程调用虚引用相关方法释放直接内存。

        终结器引用:必须配合引用队列来使用,在垃圾回收时,终结器引用入队(被引用对象暂                                    时没有被回收),再由Finalizer线程通过终结器引用找到被引用对象并调用它                                  的finalize方法,第二次GC时才能回收被引用对象。 

        

2.垃圾回收算法

        2.1标记清除  Mark Sweep     优点:速度快,缺点:容易造成内存碎片

        2.2标记整理  Mark Compact  优点:无内存碎片 , 缺点:效率低

        2.3复制算法   Copy                优点:无内存碎片 , 缺点:占用双倍的内存

        Copy分为 From  和 To 两块

3.分带垃圾回收

        实际在JVM垃圾回收器中不会说只用一种算法,会结合使用,协同工作,名为分带回收。

  1. 对象首先分配在伊甸园区域
  2. 新生代空间不足时,触发Minor GC,伊甸园和from存活的对象使用Copy复制到to中,存活对象的年龄+1,并且交换From  To。Minor GC会引发 stop the world就是暂停用户的其它线程方法,等垃圾回收结束,才恢复运行。
  3. 当对象寿命超过阈值时,最大寿命为15(4bit),会晋升老年代。
  4. 当老年代空间不足时,会先尝试触发 Minor GC,如果空间仍不足,那么会触发 Full GC,STW时间更长。
  5. 若老年代空间也不够了,那么会触发 OutOfMemoryError.

如果有个大对象,即使是新生代没有任何东西也放不下,若老年代空间足够会直接放到老年代,此时不会引起GC。

一个线程内的OutOfMemoryError不会导致Java进程的结束。

相关参数

4.垃圾回收器

        4.1串行

        单线程、堆内存较小、适合个人电脑

        4.2吞吐量优先

        目标:让单位时间内STW时间最短   如一小时两次,每次0.2秒,共0.4秒

        多线程、堆内存较大、多核CPU

        4.3响应时间优先  

        目标:让单次STW时间最短  如一小时五次,每次0.1秒,共0.5秒

        多线程、堆内存较大、多核CPU

        4.4Garbage First       G1

5.垃圾回收调优

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值