JVM内存回收和引用状态

GC垃圾回收和引用状态的关系:

        java垃圾回收机制,就是对堆内存进行回收。具体又划分为新生代和老年代,目前比较流行的回收算法是可达性性算法,从GC Roots开始按照一定的逻辑判断对象是否可达,不可达说明对象已死亡。(另外的常见算法为引用计数算法,当对象被引用计数器+1,当变量更改对象的引用计数器-1,当A持有B的引用,B持有A的引用,就会出现循环引用,导致垃圾不会被回收)基于此java向用户提供了四种引用。

 

新生代(Eden,survivor[from,to]):对象被new出来,被分配在Eden区域,当其占用空间达到一定的阈值,触发Monitor GC。仍然被引用的对象被存活下来,被复制到Survivor区域from块。当再次触发Monitor GC 之前from区域的对象仍被引用(将Eden区域和from区域的对象复制到to区域),年龄加1。当年龄超过一定的阈值(可以通过 -XX:MaxTenuringThreshold=<N> 指定)对象将晋升为老年代

老年代:

垃圾收集算法:清除,压索,复制

 

新生代相比与老年代会频繁的触发GC( 设置比例 -XX:NewRatio=2 新生代占堆空间1/3)。

不管在日常生活中还是在程序中,28法则适用与挺多场景。一个系统频繁调用的业务往往是那百分之二十,即大多数对象使用了一次即被销毁,所以设置Eden与Survivor的比例(默认为8,即Edeb占新生代8/10,另外两块区域各占1/10,可以通过 -XX:SurvivorRatio=8 设置)

 

 

强引用:通过new关键字产生,当引用可达时,不会被回收。

软引用:在jvm发送OOM之前,可以回收这部分的内存。

弱引用: 虚引用是哪些如果引用未被使用,就会在最近的一次GC的时候被回收。(通常用在内部类中,不影响外部类被回收,例如ThreadLocal)

虚引用:在任何时候都可能被回收。

 

对象可达性:

强引用:可以被转换为若引用,软引用。可以直接被finalize.

软引用:强引用,弱引用。 finalize.

弱引用:强引用,软引用。finalize.

幻想引用:出现finalize之后。Unreachable(不可达)

 

 

对四种引用状态的说明,引用公众号:代码荣耀

在Java语言中,除了基本数据类型外,其他的都是指向各类对象的对象引用;Java中根据其生命周期的长短,将引用分为4类。

 

1 强引用

 

特点:我们平常典型编码Object obj = new Object()中的obj就是强引用。通过关键字new创建的对象所关联的引用就是强引用。 当JVM内存空间不足,JVM宁愿抛出OutOfMemoryError运行时错误(OOM),使程序异常终止,也不会靠随意回收具有强引用的“存活”对象来解决内存不足的问题。对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null,就是可以被垃圾收集的了,具体回收时机还是要看垃圾收集策略。

 

2 软引用

 

特点:软引用通过SoftReference类实现。 软引用的生命周期比强引用短一些。只有当 JVM 认为内存不足时,才会去试图回收软引用指向的对象:即JVM 会确保在抛出 OutOfMemoryError 之前,清理软引用指向的对象。软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。后续,我们可以调用ReferenceQueue的poll()方法来检查是否有它所关心的对象被回收。如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。

 

应用场景:软引用通常用来实现内存敏感的缓存。如果还有空闲内存,就可以暂时保留缓存,当内存不足时清理掉,这样就保证了使用缓存的同时,不会耗尽内存。

 

3 弱引用

 

弱引用通过WeakReference类实现。 弱引用的生命周期比软引用短。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。由于垃圾回收器是一个优先级很低的线程,因此不一定会很快回收弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

 

应用场景:弱应用同样可用于内存敏感的缓存。

 

4 虚引用

 

特点:虚引用也叫幻象引用,通过PhantomReference类来实现。无法通过虚引用访问对象的任何属性或函数。幻象引用仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

ReferenceQueue queue = new ReferenceQueue ();

PhantomReference pr = new PhantomReference (object, queue); 

程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取一些程序行动。

 

应用场景:可用来跟踪对象被垃圾回收器回收的活动,当一个虚引用关联的对象被垃圾收集器回收之前会收到一条系统通知。

 

jvm相关参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: JVM内存模型是Java虚拟机的内存管理模型,它用于管理Java应用程序的内存使用。JVM内存模型包括以下几个区: 1. 程序计数器:保存了当前线程执行的字节码的行号指示器,它是一个较小的内存区域,不会对Java对象造成影响。 2. 虚拟机栈:保存了Java方法执行的内部状态,每个方法执行的时候都创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。 3. 本地方法栈:与虚拟机栈类似,但专门用于执行本地(Native)方法。 4. 堆:是Java虚拟机所管理的最大一块内存区域,用于存放对象实例。所有对象实例以及数组都在堆上分配内存。 5. 方法区:存储了类信息、常量、静态变量、即时编译器编译后的代码等数据。 JVM通过这些内存区域管理Java应用程序的内存,保证程序的正常运行。 ### 回答2: JVM(Java虚拟机)内存模型是用来管理Java程序运行时所需的内存的。JVM内存模型主要由以下五个区域组成,分别是:堆、方法区(也称为永久代)、虚拟机栈、本地方法栈和程序计数器。 1. 堆(Heap):堆是JVM内存中最大的一块区域,被用来存储对象实例和数组。堆被所有线程共享,而且在JVM启动时就创建了。堆被进一步划分为新生代和老年代。新生代包括Eden区和两个Survivor区(From和To区),它们主要用于存储新创建的对象。老年代用于存储长期存活的对象。 2. 方法区(Method Area):方法区用来存储类的元数据信息,包括类的结构、常量、静态变量、即时编译器编译后的代码等。另外,方法区还包含一个常量池,用于存储类的常量。 3. 虚拟机栈(VM Stack):虚拟机栈用于存储每个线程的方法调用和局部变量信息。每个线程在执行方法时都在虚拟机栈中创建一个栈帧,栈帧包含了方法局部变量表、操作数栈、动态链接、方法出口等信息。 4. 本地方法栈(Native Method Stack):本地方法栈类似于虚拟机栈,但是它是为执行本地(即非Java)方法而设计的。它的功能和虚拟机栈类似。 5. 程序计数器(Program Counter):程序计数器是每个线程私有的,用于存储当前正在执行的指令地址。在任意时刻,一个线程都只能执行一个方法,程序计数器记录了当前线程执行的字节码指令位置,当线程被中断或者被调度时,可以恢复到正确的执行位置。 这些内存区域在JVM内存模型中各自承担着不同的职责,通过合理的调配和管理,可以提高Java程序的性能和安全性。 ### 回答3: JVM(Java虚拟机)内存由多个不同的区域组成,用于存储不同类型的数据。主要的JVM内存区域包括: 1. 程序计数器(Program Counter):用于记录当前线程执行的字节码指令的地址。在多线程环境下,每个线程都有自己的程序计数器。 2. Java栈(Java Stack):用于存储局部变量、方法参数、操作数栈和方法调用的信息。每个方法在执行时都创建一个栈帧,栈帧包含了方法的局部变量和操作数栈信息。 3. 本地方法栈(Native Method Stack):用于存储执行本地方法(非Java代码实现的方法)的信息。 4. 堆(Heap):用于存储Java对象实例和数组。堆是JVM内存中最大的一块区域,可以被所有线程共享。在堆中,对象实例的分配和回收垃圾回收器负责。 5. 方法区(Method Area):用于存储JVM加载的类信息、常量、静态变量、方法字节码等。方法区也被称为永久代(Permanent Generation),尽管在Java 8中,永久代已经被元空间(Metaspace)取代。 6. 运行时常量池(Runtime Constant Pool):是方法区的一部分,用于存储编译时生成的字面量和符号引用。常量池中的内容包括类和接口的全限定名、字段和方法的名称和描述符、字符串常量等。运行时常量池是每个类或接口的常量池表的运行时表示形式。 除了以上主要的内存区域外,还有一些其他的内存区域,比如直接内存(Direct Memory),用于存储通过NIO类库分配的字节缓冲区。直接内存并不是JVM中的一部分,但是它可以被JVM管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值