Java内存与垃圾收集知识总结

时间:2022-09-02 13:17:09

总结一下关于Java内存的知识,今天我不生产知识,我只是知识的搬运工。

1.运行时数据区域

java虚拟机在执行JAVA程序的过程中会把它所管理的内存划分为若干个不同的数据区域。

由所有线程共享的数据区

  • 堆[Heap]:

    Java堆是Java虚拟机管理的内存中最大的一块,此内存区域的唯一目的就是存放对象实例。所有的对象实例以及数组都要在堆上分配,但随着虚拟机技术的发展,这个变得不这么绝对。Java堆是垃圾收集其管理的主要区域,因此很多时候也被称为GC堆。根据虚拟机规范的规定,Java堆可以是处于物理上不连续的内存空间中,只要逻辑上是连续的即可。

  • 方法区[Method Area]:

    方法区用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

线程隔离的数据区:

  • 虚拟机栈[VM]:

    虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

  • 本地方法栈[Native Method Stack]:

    本地方法栈与虚拟机栈发挥的作用非常相似,区别就在于它是为Native方法服务的。

  • 程序计数器[Program Counter Register]:

    程序计数器是一块儿较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。

上面是运行时数据非配的区域,我们了解之后,关注下面的重头戏,JVM很重要的垃圾回收机制。

2.对象的生命旅程

为了避免程序员繁重的内存管理工作,JVM提供了垃圾回收机制。

2.1对象是否可达

我们通过可达性分析来判断一个对象是否存活。
这个算法的基本思路就是通过一系列的成为“GC Roots”的对象作为起始点,从这些点开始写向下搜索,搜索走过的路径成为引用链,当一个对象到GC Roots没有任何引用链相连(用图论的话说就是从GC Roots到这个对象不可达时),则证明这些对象是不可用的。
在Java中,可作为GC Roots的对象包括下面几种:

  • 虚拟机栈中引用的对象
  • 方法区中静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI引用的对象

即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候他们暂时处于缓刑阶段,如果要真正需要宣告一个对象死亡,至少要经历两次标记的过程。
第一次标记是看该对象是否有必要执行finalize()方法,如果有必要会放入F-Queue队列中。
第二次标记前,对象可以通过重新与引用链上的任何一个对象建立关联,则可以逃脱被回收的命运,否则就会被回收。

2.2方法区回收

我们大多数时候认为方法区是属于永久代的,因为永久代的回收成本较高,所以我们可以选择不对永久代就行回收,但也可以对其进行回收。永久代的垃圾回收主要会后两部分内容:废弃常量和无用的类。
无用的类需要同时满足下面三个条件:

  • 该类的所有实例都已经被回收,也就是Java堆中不存在该类的任何实例。
  • 加载该类的ClassLoader已经被回收。
  • 该类对应的java.lang.class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

虚拟机可以对满足上述3个条件的无用类进行回收。

2.3四种引用

由上文可知,一个对象是否被回收,和引用有很大关系,Java语言提供了四个级别的引用

  • 强引用

    强引用是我们最常见的Object o = new Object()这类引用,只要强引用还存在,垃圾回收器就永远不会回收被引用的对象。

  • 软引用

    软引用用来描述一些还有用但并非必须的对象,对于软引用关联的这对象,当内存资源紧张的时候,才会触发GC。是GC二次回收的对象,只有当回收软引用对象空间仍不足是,才会抛出内存异常对象。
    常用方法有SoftRefrence<T> tSoftRef = new SoftRefrence<T>(t)tSoftRef.get()方法
    每个软引用都可以附带一个引用队列,当对象的可达性状态发生改变时(由可达变成不可达),软引用对象就会进入引用队列,通过这个引用队列可以跟踪那个对象的回收情况,在初始化时加入一个引用队列的参数即可。

  • 弱引用

    弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作室,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。用WeakRefrence实现弱引用,和软引用一样,有两种初始化的方法。

  • 虚引用

    最弱的一种引用关系,一个对象有没有虚引用,完全不会对其生存时间构成影响,随时都可能被垃圾回收器回收。虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收的过程。也无法通过get方法获得对象的实例。当垃圾回收器准备回收一个对象是,如果发现它有虚引用,就会在回收对象后,将这个虚引用加入引用队列,已通知应用程序对象的回收情况。可以使用PhantomRefrence实现虚引用。

3.垃圾回收算法

3.1单打独斗的算法

  • 引用计数法

    对于一个对象A,给其配备一个整型的计数器,只要任何一个对象引用了A,则A的引用计数器就加1,当引用失效后,引用计数器就减1,只要对象的引用计数器为0,则对象A就不可以在被引用,会被回收掉。
    但这种算法那有两个问题:(1)无法处理循环引用的情况,会引起内存泄露(2)每次引用产生和消除的时候,都需要伴随一个计数器变化的操作,影响性能。

  • 标记清除法

    如其名,分为两个阶段。标记阶段,实现通过根节点,标记所有从根节点开始的可达对象,因此,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清楚所有未被标记的对象。标记清楚算法可能产生的最大问题就是空间碎片。

  • 复制算法

    它将可用内存按照用量划分为大小相等的两块,每次只是用其中的一块,当这一块的内存用完了,就将还存活的对象复制到另外一块上去,然后再将已使用的内存空间一次性清理掉。这样使得每次都是对整个半区进行内存回收,不用考虑内存碎片等复杂情况,只需要移动堆顶指针,按顺序分配内存即可。这种方法的缺陷在于代价太大,将可用内存缩小到了原来的一半。所以在老年代这种每次回收只有一小部分甚至没有对象被回收的场景不适合用这种方法。

  • 标记-整理算法

    根据老年代的特点提出的算法。第一阶段标记过后,让所有存活的对象都向一端移动,然后直接清理掉端边界的内存。

3.2 集众长,分代收集算法

结合java对象的生存特点,提出了分代收集算法,结合上面各种算法的优点。
分代算法根据对象的特点将内存区间分成几块
Java内存与垃圾收集知识总结

  • 新生代

    存放年轻对象的空间。年轻对象是指刚刚创建的,或者经历垃圾回收次数不多的对象。分为Eden区间,SurvivorFrom空间和SurvivorTo空间。通常是8:1:1,因为大部分新生对象都是朝生夕灭的,垃圾对象远远多于存活对象。
    在垃圾回收时,eden区的存活对象会被复制到未使用的Survivor空间中(假设是to),正在使用的Survivor空间(假设是From)中的年轻对象也会被复制到to空间中(大对象,或者老年对象会直接进入老年代,如果to空间已满,则对象直接进入老年代)。此时,eden空间和from空间中的剩余对象就是垃圾对象,可以直接清空,to空间则存放此次回收后仍然存货的对象。这种改进的复制算法,既保证了空间的连续性,又避免了大量的内存空间的浪费。
    通过参数SurvivorRadio来设置,即Survivor/Enden ,默认是8 。
    新生代满了或者区域不足触发的是MinorGC。

  • 老年代

    在老年代中,几乎所有的对象都是经过几次垃圾回收后依然得以存活的。因此可以认为这些对象在一定时间内会常驻内存。如果使用复制算法,代价很到,一般使用标记-清除或者标记-整理算法。
    参数:Xms设置初始堆大小,Xmx设置最大堆大小,NewRadio设置老年代与新生代的比例,老年代加新生代的大小之和即堆的大小。
    什么时候进入老年代呢?
    大对象:PretenureSizeThreshold。单位是字节。默认情况下是0,也就是不指定晋升大小,一切由运行情况决定。
    老年对象:MaxTenuringThreshold。默认15,也就是说最多经历15次GC,第16次GC的时候就会进入老年代。
    新生代回收频率高,每次耗时也短。老年代回收频率低,但是会消耗更多的时间。
    老年代满了触发的是FullGC,经常会伴随至少一次的MinorGC,比MinorGC慢10倍以上。

  • 永久代?NO!MetaSpace!

    在JDK1.6和JDK1.7的版本中,方法区可以理解成永久代,准确的说是JVM使用永久代来实现方法区。这里存储类信息和元数据。可以通过参数PermSize和MaxPerSize制定大小。
    但是这样会很明显面临一个问题,就是不够灵活,很容易溢出。
    所以在JDK1.8中,彻底移除了永久代 ,取而代之的是MetaSpace,使用本地内存存储类信息和元数据。
    此处参见下面两个链接的内容:
    Java PermGen 去哪里了?
    Java 8新特性探究(九)跟OOM:Permgen说再见吧

今天就到这里了,明天总结关于垃圾收集器的知识。
参考资料:
《深入理解Java虚拟机》
《实战Java虚拟机》

Java内存与垃圾收集知识总结的更多相关文章

  1. 求你了,再问你Java内存模型的时候别再给我讲堆栈方法区了…

    GitHub 4.1k Star 的Java工程师成神之路 ,不来了解一下吗? GitHub 4.1k Star 的Java工程师成神之路 ,真的不来了解一下吗? GitHub 4.1k Star 的 ...

  2. Java内存原型分析&colon;基本知识

    转载: Java内存原型分析:基本知识 java虚拟机内存原型 寄存器:我们在程序中无法控制 栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 堆:存放用new产生的数据 静 ...

  3. java基础知识(四)java内存机制

    Java内存管理:深入Java内存区域 上面的文章对于java的内存管理机制讲的非常细致,在这里我们只是为了便于后面内容的理解,对java内存机制做一个简单的梳理. 程序计数器:当前线程所执行的字节码 ...

  4. 硬件内存模型到 Java 内存模型,这些硬核知识你知多少?

    Java 内存模型跟上一篇 JVM 内存结构很像,我经常会把他们搞混,但其实它们不是一回事,而且相差还很大的,希望你没它们搞混,特别是在面试的时候,搞混了的话就会答非所问,影响你的面试成绩,当然也许你 ...

  5. Java-100天知识进阶-Java内存-知识铺(四)

    知识铺: 致力于打造轻知识点,持续更新每次的知识点较少,阅读不累.不占太多时间,不停的来唤醒你记忆深处的知识点. 1.Java内存模型是每个java程序员必须掌握理解的 2.Java内存模型的主要目标 ...

  6. 【Java虚拟机4】Java内存模型(硬件层面的并发优化基础知识--缓存一致性问题)

    前言 今天学习了Java内存模型第一课的视频,讲了硬件层面的知识,还是和大学时一样,醍醐灌顶.老师讲得太好了. Java内存模型,感觉以前学得比较抽象.很繁杂,抽象. 这次试着系统一点跟着2个老师学习 ...

  7. java的线程安全、单例模式、JVM内存结构等知识学习和整理

    知其然,不知其所以然 !在技术的海洋里,前路漫漫,我一直在迷失着自我. 欢迎访问我的csdn博客,我们一同成长! "不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!" 博 ...

  8. Java虚拟机的内存管理----垃圾收集器

    1.Serial收集器 优点,是简单而高效,单线程避免了线程交互的开销. 缺点,进行垃圾回收时需要Stop the world(暂停所有用户线程). 2.ParNew收集器 它是Serial收集器的多 ...

  9. java内存回收需要了解的知识

    你是否有过这样的经历,跑得好好的Java进程,突然就瘫痪了?多数Java进程瘫痪的原因可以从java虚拟机层面找到原因. 1.什么情况下会执行gc 为了了解我们的系统为什么会不停fgc,我们需要先了解 ...

随机推荐

  1. CentOS下Apache配置多域名或者多端口映射

    CentOS下Apache默认网站根目录为/var/www/html,假如我默认存了一个CI项目在html文件夹里,同时服务器的外网IP为ExampleIp,因为使用的是MVC框架,Apache需开启 ...

  2. 搭建DHCP服务器以及DHCP中继服务器

    一.DHCP服务器   1.首先配置DHCP服务器的IP地址(DHCP服务器网卡桥接在VMnet1)   .配置好IP后重启DHCP服务 3.安装DHCP服务器,在这里我用的是YUM安装的(关于YUM ...

  3. 桥接 NAT HOST-ONLY

    无论是vmware,virtual box,virtual pc等虚拟机软件,一般来说,虚拟机有三种网络模式: 1.桥接 2.NAT 3.Host-Only 桥接 桥接网络是指本地物理网卡和虚拟网卡通 ...

  4. Java课程设计——计算器

    1.团队课程设计博客链接 http://www.cnblogs.com/yuanj/p/7072137.html 2.个人负责模块或任务说明 确定课题并进行任务分工 编写计算器删除,清零,清空,小数点 ...

  5. create react app 项目部署在Spring&lpar;Tomcat&rpar;项目中

    网上看了许多,大多数都是nginx做成静态项目,但是这样局限性太多,与Web项目相比许多服务端想做的验证都很麻烦,于是开始了艰难的探索之路,终于在不经意间试出来了,一把辛酸... 正常的打包就不说了. ...

  6. Codeforces1101F Trucks and Cities 【滑动窗口】【区间DP】

    题目分析: 2500的题目为什么我想了这么久... 考虑答案是什么.对于一辆从$s$到$t$的车,它有$k$次加油的机会.可以发现实际上是将$s$到$t$的路径以城市为端点最多划分为最大长度最小的$k ...

  7. bat、sh等批处理文件(脚本文件)

    批处理文件(batch file):也被称为批处理程序或脚本,可以简化日常或重复性任务.本质是无格式的文本文件,它包含一条或多条命令.(1).bat是dos下的批处理文件,在window系统上执行的文 ...

  8. Redis Windows 安装

    摘自:https://www.cnblogs.com/M-LittleBird/p/5902850.html 一.下载windows版本的Redis 去官网找了很久,发现原来在官网上可以下载的wind ...

  9. mysql创建外链失败1005错误解决方法

    mysql创建外链失败1005错误解决方法 错误号:1005错误信息:Can't create table 'webDB.#sql-397_61df' (errno: 150)解决方法 错误原因有四: ...

  10. java操作Excel之POI(1)

    一.新建工作簿.sheet.单元格 public static void main(String[] args) throws Exception { Workbook wb = new HSSFWo ...