一、Java GC 概念说明

Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢。这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制。概括地说,该机制对JVM(Java Virtual Machine)中的内存进行标记,并确定哪些内存需要回收,根据一定的回收策略,自动的回收内存,永不停息(Nerver Stop)的保证JVM中的内存空间,防止出现内存泄露和溢出问题。

Java GC机制主要完成3件事:确定哪些内存需要回收,确定什么时候需要执行GC,如何执行GC。下面我们将从4个方面学习Java GC机制,1,内存是如何分配的;2,如何保证内存不被错误回收(即:哪些内存需要回收);3,在什么情况下执行GC以及执行GC的方式;4,如何监控和优化GC机制。

二、Java内存区域划分

了解Java GC机制,必须先清楚在JVM中内存区域的划分。在Java运行时的数据区里,由JVM管理的内存区域分为下图几个模块:

1. 程序计数器(Program Counter Register)

程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,可以理解为是当前线程的行号指示器。字节码解释器在工作时,会通过改变这个计数器的值来取下一条语句指令。

每个程序计数器只用来记录一个线程的行号,所以它是线程私有(一个线程就有一个程序计数器)的。

如果程序执行的是一个Java方法,则计数器记录的是正在执行的虚拟机字节码指令地址;如果正在执行的是一个本地(native,由C语言编写完成)方法,则计数器的值为Undefined,由于程序计数器只是记录当前指令地址,所以不存在内存溢出的情况,因此,程序计数器也是所有JVM内存区域中唯一一个没有定义OutOfMemoryError的区域。

2. Java虚拟机栈(Java Virtual Machine Stacks)

一个线程的每个方法在执行的同时,都会创建一个栈帧(Statck Frame),栈帧中存储的有局部变量表、操作站、动态链接、方法出口等,当方法被调用时,栈帧在JVM栈中入栈,当方法执行完成时,栈帧出栈。

局部变量表中存储着方法的相关局部变量,包括各种基本数据类型,对象的引用,返回地址等。在局部变量表中,只有long和double类型会占用2个局部变量空间(Slot,对于32位机器,一个Slot就是32个bit),其它都是1个Slot。需要注意的是,局部变量表是在编译时就已经确定好的,方法运行所需要分配的空间在栈帧中是完全确定的,在方法的生命周期内都不会改变。

虚拟机栈中定义了两种异常,如果线程调用的栈深度大于虚拟机允许的最大深度,则抛出StatckOverFlowError(栈溢出);不过多数Java虚拟机都允许动态扩展虚拟机栈的大小(有少部分是固定长度的),所以线程可以一直申请栈,直到内存不足,此时,会抛出OutOfMemoryError(内存溢出)。

每个线程对应着一个虚拟机栈,因此虚拟机栈也是线程私有的。

3. 本地方法栈(Native Method Stacks)

本地方法栈在作用,运行机制,异常类型等方面都与虚拟机栈相同,唯一的区别是:虚拟机栈是执行Java方法的,而本地方法栈是用来执行native方法的,在很多虚拟机中(如Sun的JDK默认的HotSpot虚拟机),会将本地方法栈与虚拟机栈放在一起使用。

本地方法栈也是线程私有的。

4. 堆区(Heap) (新生代和旧生代)

堆区是理解Java GC机制最重要的区域,没有之一。在JVM所管理的内存中,堆区是最大的一块,堆区也是Java GC机制所管理的主要内存区域,堆区由所有线程共享,在虚拟机启动时创建。堆区的存在是为了存储对象实例,原则上讲,所有的对象都在堆区上分配内存(不过现代技术里,也不是这么绝对的,也有栈上直接分配的)。

一般的,根据Java虚拟机规范规定,堆内存需要在逻辑上是连续的(在物理上不需要),在实现时,可以是固定大小的,也可以是可扩展的,目前主流的虚拟机都是可扩展的。如果在执行垃圾回收之后,仍没有足够的内存分配,也不能再扩展,将会抛出OutOfMemoryError:Java heap space异常。

5. 方法区(Method Area)(永久代)

方法区是各个线程共享的区域,用于存储已经被虚拟机加载的类信息(即加载类时需要加载的信息,包括版本、field、方法、接口等信息)、final常量、静态变量、编译器即时编译的代码等。

方法区在物理上也不需要是连续的,可以选择固定大小或可扩展大小,并且方法区比堆还多了一个限制:可以选择是否执行垃圾收集。一般的,方法区上执行的垃圾收集是很少的。但这也不代表着在方法区上完全没有垃圾收集,其上的垃圾收集主要是针对常量池的内存回收和对已加载类的卸载。

在方法区上进行垃圾收集,条件苛刻而且相当困难,效果也不令人满意,所以一般不做太多考虑,可以留作以后进一步深入研究时使用。

在方法区上定义了OutOfMemoryError:PermGen space异常,在内存不足时抛出。

6. 新生代、旧生代、永久代

虚拟机中共划分为三个代:新生代、旧生代、永久代。年轻代和年老代的划分是对垃圾收集影响比较大的。

所有新生成的对象首先都是放在新生代的;旧生代中存放的都是一些生命周期较长的对象。永久代用于存放静态文件,如Java类、方法等。永久代对垃圾回收没有显著影响。

三、Java对象的访问方式

一个Java的引用访问涉及到3个内存区域:JVM栈,堆,方法区。

以最简单的本地变量引用:Object obj = new Object()为例:

Object obj表示一个本地引用,存储在JVM栈的本地变量表中,表示一个reference类型数据;

new Object()作为实例对象数据存储在堆中;

堆中还记录了Object类的类型信息(接口、方法、field、对象类型等)的地址,这些地址所执行的数据存储在方法区中;

在Java虚拟机规范中,对于通过reference类型引用访问具体对象的方式并未做规定,目前主流的实现方式主要有两种:

1. 通过句柄访问:

通过句柄访问的实现方式中,JVM堆中会专门有一块区域用来作为句柄池,存储相关句柄所执行的实例数据地址(包括在堆中地址和在方法区中的地址)。这种实现方法由于用句柄表示地址,因此十分稳定。

2. 通过直接指针访问:

通过直接指针访问的方式中,reference中存储的就是对象在堆中的实际地址,在堆中存储的对象信息中包含了在方法区中的相应类型数据。这种方法最大的优势是速度快,在HotSpot虚拟机中用的就是这种方式。

四、参考资料

1.《JAVA编程思想》第5章

2.《Java深度历险》Java垃圾回收机制与引用类型

3.《深入理解Java虚拟机:JVM高级特效与最佳实现》,第2-3章

java gc机制新区域旧屋_Java 内存回收机制——GC机制-Go语言中文社区相关推荐

  1. java怎么导出有模板的表格_java用模板导出数据表格-Go语言中文社区

    1.创建表格: 2.编写导出的controller; @PostMapping("/cust/report/customer/export") public void export ...

  2. Java元数据区的概念_java之元数据(metadata)-Go语言中文社区

    什么是元数据? 元数据是指用来描述数据的数据,更通俗一点,就是描述代码间关系,或者代码与其他资源(例如数据库表)之间内在联系的数据.在一些技术框架,如struts.EJB.hibernate就不知不觉 ...

  3. java调用百度翻译_Java调用百度API实现翻译-Go语言中文社区

    下面是Java调用百度API实现翻译的具体步骤: 一.在写代码之前先在在百度翻译平台中,申请APP_ID 申请地址申请的详见点击打开链接 申请之后,会得到APP_ID和SECURITY_KEY 二.j ...

  4. java web短信接口_Java调用WebService短信接口-Go语言中文社区

    一.WebService接口说明 以http post的形式进行发送,上面是请求信息,下面是返回值. 接口文档返回值部分介绍. 二.Java代码,其中的MD5工具类请参照我的其他文章,或自己找一个MD ...

  5. java 航班_Java实现简单航班查询系统-Go语言中文社区

    #java实现简单航班管理系统 题目要求:声明一个Flight(航班)类,该类包含private域航班号(如:CA1430),起飞时间(如:10:15AM),到达时间(如:2:30PM).为该类声明合 ...

  6. java蓝桥杯dfs_第七届 蓝桥杯决赛 Java B组 打靶 解题报告(DFS,回溯,全排列)-Go语言中文社区...

    题目: 打靶 小明参加X星球的打靶比赛. 比赛使用电子感应计分系统.其中有一局,小明得了96分. 这局小明共打了6发子弹,没有脱靶. 但望远镜看过去,只有3个弹孔. 显然,有些子弹准确地穿过了前边的弹 ...

  7. java gc内存_Java内存模型和GC机制

    最近学习Python的GC机制时,想到了java的GC,忘得差不多了,(⊙﹏⊙)b!!这里便做一下回顾总结.推荐周志明译本的<深入理解Java虚拟机>. 1. Java内存模型 1.1 程 ...

  8. java gc原理_Java内存管理以及GC工作原理

    1.内存管理简介 内存管理的职责为分配内存,回收内存. 没有自动内存管理的语言/平台容易发生错误. 典型的问题包括悬挂指针问题,一个指针引用了一个已经被回收的内存地址,导致程序的运行完全不可知. 另一 ...

  9. java 终结此段代码并重新运行_Java垃圾回收

    好久没看关于java的书了, 最近, 看了James Gosling的<>, 做了一些读书笔记. 这部分是关于垃圾回收的. 1.垃圾回收 对象是使用new创建的, 但是并没有与之相对应的d ...

最新文章

  1. 不从事编程、学python有用吗-为什么你觉得C语言什么都不能做,学了没用?不可能的...
  2. 隐藏input边框(ie6、ie7)
  3. 网络协议基础:“工作中模模糊糊的概念,这次终于理顺了!”
  4. 定时任务(Spring Cloud Task)
  5. 操作目录下的文件或目录
  6. 可扩展的Web架构和分布式系统
  7. 判断日期是否为当月最后一天_对比Excel,怎么用Python获取指定月最后一天的日期...
  8. 监控zabbix 服务并在异常时python 邮件报警
  9. php主控,IcePHP框架中的快速后台中的通用CRUD功能框架(五) SCrud 主控类
  10. 通过mapreduce把mysql的数据读取到hdfs
  11. hdu5033 Building 单调队列
  12. ORM正向和反向查询
  13. 流媒体压力测试工具—推拉流
  14. Makefile编写实例
  15. noip题库 —— 4.7反质数
  16. 懂车帝新能源汽车销量分析
  17. cfdpost导出图片_CFD-POST出数据方法.pdf
  18. 学习篇之华为快应用的开发(一)
  19. 西安交大计算机考研软件工程编程题库(二十四)
  20. 全面解析电商数据挖掘之关联算法

热门文章

  1. 获奖名单出炉,快来看看有没有你!
  2. 数据可视化揭晓NBA球星顶薪背后的真相
  3. K8S精华问答 | K8S 是什么?不是什么?
  4. 微服务落地,我们在考虑什么?| 技术头条
  5. linux磁盘配额edquota,Linux磁盘配额(Quota)
  6. Ant Design Vue页面数据复制
  7. Java各个类型转化
  8. IntelliJ IDEA 单行注释调整
  9. Linux 中文无法显示或显示方块
  10. JavaScript 中,break , continue , return 的区别