一、内存分配
1.JVM体系结构
2.运行时数据区域
3.内存分配
二、内存回收
1.垃圾收集算法
2.垃圾收集器
三、相关参考
一、内存分配
JVM体系结构

在了解自动内存管理的内存分配之前,我们先看下JVM的体系结构。代码编译的结果是从本地机器码转变为字节码,经过类加载器加载到虚拟机后才能执行程序。JVM的体系结构主要如下图所示:

JVM体系结构

运行时数据区域

在上图中我们可以清楚地看到,JVM在执行Java程序的过程中会把它管理的内存划分为若干个不同的数据区域,分别是程序计数器、Java虚拟机栈、本地方法栈、方法区(包括运行时常量池)、堆。下面逐一介绍。

程序计数器(Program Counter Register)
线程私有,不会出现OOM,是一块较小的内存空间,作用可以看作是当前线程所执行的字节码的行号指示器,因为JVM的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,各条线程间的计数器互不影响,独立存储。

Java虚拟机栈(Java Virtual Machine Stacks)
线程私有,每创建一个线程,虚拟机就会为这个线程创建一个虚拟机栈,虚拟机栈描述的是Java方法执行的内存模型,每调用一个方法,就会生成一个栈帧(Stack Frame)用于存储方法的本地变量表、操作栈、方法出口等信息,当这个方法执行完后,就会弹出相应的栈帧。这部分区域,如果请求的栈的深度过大,虚拟机可能会抛出StackOverflowError异常,如果虚拟机的实现中允许虚拟机栈动态扩展,当内存不足以扩展栈的时候,会抛OutOfMemoryError异常。

本地方法栈(Native Method Stack)
线程私有,本地方法栈与虚拟机栈类似,只是在执行本地方法时使用。


线程共享,几乎所有的对象实例以及数组都是在这个区域进行分配,这里也是垃圾回收的主要区域就是这里(还可能有方法区)。Java堆可以处于物理上不连续的内存空间,只要逻辑上连续即可。从内存分配的角度看,线程共享的Java堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。从内存回收的角度看,Java堆中可细分为新生代和老年代,再细致点有Eden空间、From Survivor空间、To Survivor空间等。如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,就会抛出OOM异常。

堆内存

方法区
线程共享,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等信息。当方法区无法满足内存分配需求时,会抛出OOM异常。运行时常量池是方法区的一部分,主要用来存储编译时生成的字面量和符号引用。

下面这张运行时数据区域图可能更形象一点。

内存分配

大多数情况下,对象在新生代Eden区中分配,当Eden区没有足够的空间进行分配时,虚拟机将发起一次新生代GC(Minor GC)。

在设置虚拟机参数的时候,-Xmx20M -Xms20M -Xmn10M -XX:SurvivorRatio=8的含义是-Xmx与-Xms相等限制了堆大小为20MB,-Xmn表示新生代大小为10MB,剩下的10MB分配给老年代,-XX:SurvivorRatio=8表示新生代中Eden区与一个Survivor区空间比例大小为8:1,所以Eden区大小为8192K,一个Survivor区大小为1024K,新生代总可用空间为9216K。

大对象直接进入老年代,大对象是指需要连续内存空间的Java对象,比如很长的字符串及数组。长期存活的对象将进入老年代。

有道题是这样的:

问题

这道题是自己在之前遇到过的,题目本身表达有点歧义,答案是堆和字符串常量池中,当new String("abc")时,其实会先在字符串常量区生成一个abc的对象,然后new String()时会在堆中分配空间,然后此时会把字符串常量区中abc复制一个给堆中的String,故abc应该在堆中和字符串常量区。

二、内存回收
对象是否存活?

垃圾收集器在对堆进行回收前,首先需要判断对象是否存活,即是否可能再被使用。这里就要提到一个引用计数算法,每当一个对象被引用时,计数器就加1,引用失效时就减1,当计数器为0时就不可能被使用了,这是一个简单的判断对象是否存活的算法,但是Java中并没有选用,主要是因为它很难解决对象间相互循环引用的问题。

Java中判断对象是否存活,使用的是根搜索算法,基本思路就是通过一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连,这个对象就是不可用的。

Java中可以作为GC Roots对象的主要有以下几种:

1)虚拟机栈(栈帧中的本地变量表)中引用的对象
2)方法区中类静态属性引用的对象
3)方法区中常量引用的对象
4)Native方法中引用的对象

垃圾收集算法

在确定哪些内存需要回收后,接下来就是怎么回收的问题了,也就是垃圾收集算法,常用的几种如下:标记-清除算法、复制算法、标记-整理算法以及分代回收算法。

标记-清除算法
这是最基础的收集算法,首先标记出所有需要回收的对象,标记完成后统一回收掉所有被标记的对象。缺点有两个,一个是效率问题,标记和清除过程的效率不高,另一个是空间问题,标记清除后会产生大量的不连续的内存碎片。

复制算法
这个算法主要是为了解决效率问题,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块,当一块的内存用完时,将活着的对象复制到另外一块上面,然后把已经使用过的内存空间清理掉。优点是每次都是对其中一块内存进行回收,不用考虑内存碎片等情况,实现简单,运行高效,缺点是内存缩小为原来的一半。

标记-整理算法
复制收集算法在对象存活率较高时就要执行较多的复制操作,效率会变低,标记整理算法首先标记出所有需要回收的对象,之后让所有存活的对象都向一端移动,然后清理掉端边界以外的内存。

分代收集算法
根据对象的存活周期的不同将内存划分为几块。一般是把Java堆分为新生代和老年代,根据各个年代的特点采用适当地收集算法。在新生代中,每次垃圾收集时都有大量对象死去,只有少量存活,就选用复制算法,老年代中因为对象存活率高、没有额外空间进行 分配担保,就采用标记-清理或者标记-整理回收。

垃圾收集器

垃圾收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现,下面介绍几种常见的垃圾收集器。

Serial收集器
最基本、历史最悠久的收集器,在JDK 1.3.1之前是新生代收集的唯一选择,它是一个单线程收集器,在工作时必须暂停其他所有的工作线程。

ParNew收集器
Serial收集器的多线程版本,其它方面基本与Serial一致。使用-XX:+UseParNewGC开关来控制使用ParNew+Serial Old收集器组合收集内存;使用-XX:ParallelGCThreads来设置执行内存回收的线程数。

Parallel Scavenge 收集器
吞吐量优先的垃圾回收器,作用在新生代,使用复制算法,关注CPU吞吐量,即运行用户代码的时间/总时间。其它收集器主要尽可能地缩短垃圾收集时用户线程的停顿时间,停顿时间短适合需要与用户交互的程序,而高吞吐量则可以最高效率地利用CPU时间,尽快地完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。

Serial Old收集器
Serial收集器的老年代版本,单线程收集器,使用标记-整理算法。

Parallel Old收集器
Parallel Scavenge 收集器的老年代版本,使用标记-整理算法,多线程,这个收集器是JDK 1.6才开始提供的,在此之前新生代的Parallel Scavenge收集器比较尴尬,只能与Serial Old搭配,性能有待提高,Parallel Old出现后与Parallel Scavenge搭配很不错。

CMS(Concurrent Mark Sweep)收集器
致力于获取最短回收停顿时间(即缩短垃圾回收的时间),使用标记清除算法,多线程,优点是并发收集(用户线程可以和GC线程同时工作),停顿小。

G1(Garbage-First)收集器
当今收集器技术发展的最前沿成果之一,G1收集器的主要特点有:
1)并行与并发 能充分利用多CPU、多核环境的硬件优势缩短Stop-The-World停顿的时间
2)分代收集 可以不需要其他收集器配合就能独立管理整个GC堆
3)空间整合 整体上的基于“标记-整理”算法及局部上的基于“复制”算法意味着运作期间不会产生内存空间碎片
4)可预测的停顿
————————————————
版权声明:本文为CSDN博主「HelloWorld搬运工」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wufaliang003/article/details/102474366

JAVA之自动内存管理机制的更多相关文章

  1. 深入理解JAVA虚拟机 自动内存管理机制

    运行时数据区域 其中右侧三个一起的部分是每个线程一份,左侧两个是所有线程共享的. 程序计数器(Program Counter Register) 英文名称叫Program Counter Regist ...

  2. JVM自动内存管理机制——Java内存区域(下)

    一.虚拟机参数配置 在上一篇<Java自动内存管理机制——Java内存区域(上)>中介绍了有关的基础知识,这一篇主要是通过一些示例来了解有关虚拟机参数的配置. 1.Java堆参数设置 a) ...

  3. JVM自动内存管理机制——Java内存区域(上)

    一.JVM运行时数据区域概述 Java相比较于C/C++的一个特点就是,在虚拟机自动内存管理机制的帮助下,我们不需要为每一个操作都写像C/C++一样的delete/free代码,所以也不容易出现内存泄 ...

  4. 【深入理解Java虚拟机】自动内存管理机制——垃圾回收机制

      Java与C++之间有一堵有内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来.C/C++程序员既拥有每一个对象的所有权,同时也担负着每一个对象生 ...

  5. 【深入理解Java虚拟机】自动内存管理机制——内存区域划分

      Java与C++之间有一堵有内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来.C/C++程序员既拥有每一个对象的所有权,同时也担负着每一个对象生 ...

  6. 2.1 自动内存管理机制--Java内存区域与内存溢出异常

    自动内存管理机制 第二章.Java内存区域与内存溢出异常 [虚拟机中内存如何划分,以及哪部分区域.什么样代码和操作会导致内存溢出.各区域内存溢出的原因] 一.运行时数据区域 Java虚拟机所管理的内存 ...

  7. 深入理解Java虚拟机(自动内存管理机制)

    文章首发于公众号:BaronTalk 书籍真的是常读常新,古人说「书读百遍其义自见」还是很有道理的.周志明老师的这本<深入理解 Java 虚拟机>我细读了不下三遍,每一次阅读都有新的收获, ...

  8. JVM介绍&自动内存管理机制

    1.介绍JVM(Java Virtual Machine,Java虚拟机) JVM是Java Virtual Machine的缩写,通常成为java虚拟机,作为Java可以进行一次编写,到处执行(Wr ...

  9. [深入理解Java虚拟机]<自动内存管理>

    Overview 走近Java:介绍Java发展史 第二部分:自动内存管理机制 程序员把内存控制的权利交给了Java虚拟机,从而可以在编码时享受自动内存管理.但另一方面一旦出现内存泄漏和溢出等问题,就 ...

随机推荐

  1. MVC授权不通过之后不执行任何自定义ActionFilter

    如下一个Action [Authorize] [F1]//自定义过滤器,继承自ActionFilter public ActionResult Index() { return View(); } 如 ...

  2. Pytorch报错:cuda runtime error (59) : device-side assert triggered at /pytorch/aten/src/THC/generic/THCTensorMath.cu:26

    Pytorch报错:cuda runtime error (59) : device-side assert triggered at /pytorch/aten/src/THC/generic/TH ...

  3. SQL优化的总结和一些避免全盘扫描的注意事项

    1.应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描. 2.应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一 ...

  4. MAVEN打包时没有将src/main/cache文件夹打到到WAR包中

    某项目中ehcache配置文件写在src/main/cache中,结果用maven打包时,得到的WAR包里面没有这个文件夹 因为maven打包时默认只打包src/main/java中的文件和src/m ...

  5. Java中Static关键字详解以及静态变量和成员变量的区别

    一.static关键字的特点 (1)修饰成员变量.成员方法(2)随着类的加载而加载(3)优先于对象存在(4)被所有对象共享(5)可以通过类名调用 它本身也可以通过对象名调用 例如:main()方法由j ...

  6. Hadoop_15_MapRduce_案例1_Wordcount 单词统计

    1.Wordcount示例编写: MapReduce采用”分而治之”的思想,把对大规模数据集的操作,分发给一个主节点管理下的各个分节点共同完成,然后通过整合各 个节点的中间结果,得到最终结果.简单地说 ...

  7. 一个线程相关的高CPU占用问题的定位

    最近在重构项目代码时,发现两个线程同时访问一个加锁的std::list队列时,会出现恶性竞争锁的现象. 具体现象是A线程总是拿不到锁,B线程抢占几次后,A才抢占到. 由于是重构项目,也无法通过回滚代码 ...

  8. Python 基础知识 (1) 持续更新

    (1)数字和表达式 当进入Python交互式的时候,Python就可以直接当成计算机使用 如 >>> 2 + 2 4 但是 当 1个整数 和 另外一个整数 相除的时候,计算的结果,只 ...

  9. Oracle 11 安装 提示环境不满足最低要求解决方案

    在 Oracle 安装包 中,找到 stage 文件夹 切入,再找到 cvu 文件夹,找到 cvu_prereq.xml 文件 ,进行编辑 新增 这一块内容. <OPERATING_SYSTEM ...

  10. 串口+RS485驱动

    其实RS485不算什么协议,只是物理层做了差分传输,AB两线的电压差来表示0,1,0,1,可靠性和距离更加好,因此,一个串口外设只能作为半双工使用,而RS232是可以全双工的. max485模块可以直 ...