`
龙飞凤舞的程序员
  • 浏览: 1305 次
  • 性别: Icon_minigender_1
文章分类
社区版块
存档分类
最新评论

跟我一起來研究Java内存管理

 
阅读更多

先看下面这个小程序

/**
 * 这个小程序作用是创建一个大约1MB的对象
 * 以下参数为运行设置中的VM Arguments参数
 * -verbose:gc
 * -XX:+PrintGCDetails
 * -Xms20M 
 * -Xmx20M
 * -Xmn10M
 * @author qianl
 *
 */
public class Test {

	public static int _1M = 1024 * 1024;
	
	public static void main(String[] args) throws InterruptedException {
		byte[] b1;
		b1 = new byte[1 * _1M];
	}

}

先解释一下VM Arguments参数:
* -verbose:gc : 输出GC的详细信息
* -XX:+PrintGCDetails : 打印GC工作的内存变化详细信息
* -Xms20M : 堆最小值
* -Xmx20M : 堆最大值
* -Xmn10M : 分配给新生代区(后面将会讲解)的大小

下面是运行后,控制台的输出:


如果英文不好,看着费劲的,下面我照着翻译一下

接下来,我们一起來分析一下

在VM Arguments设置中,我们将堆总空间设置为20M,且不可扩展,其中10M分给新生代,剩余10M分给了老年代。可能有个疑问了,中间的 “PSOldGen total 10240K”,确实刚好有10M,可是,这一句 “PSYoungGen total 8960K, used 1485K” ,哪有10M。大家看这一句下面的信息,eden的7680K,from space的1280K,to space的1280K,这三个加起来,是不是刚好10240K = 10M呢。

这里面有个细节,新生代大小,具体指的是一个eden区加上一个Survivor(就是上面的from space和to space)区。我们给新生代分配的10M,实际上是分给了三个区域,一个eden区和两个Survivor区,从数字可以看出,它们默认的分配比例为8:1:1,当然,可以手动设置的,感兴趣的可以自己查一下。所以上面中,新生代的total为8960K(eden:7680K,Survivor:1280K)。
PS : 我在网上看了一下,对于Survivor还有另外一种解释,from space和to space共同构成Survivor区,eden和Survivor构成新生代区,如果这样,那么PSYoungGen(新生代区)就应该是10240K,但实际PSYoungGen只有8960K,它没算上to space区。至于那种好,各位因人而异吧。

这里解释一下这三个区的区别:
* PSYoungGen : 主要存放新生的对象
* PSOldGen : 主要存放应用程序中生命周期长的对象
* PSPermGen : 永久保存区,方法区(参见我的另外一篇《Java虚拟机内存管理》)的对象放置在此区域

那么,Java虚拟机,是怎样安排放置对象到这些区域的呢?将上面的程序改一下:

/**
 * 此程序创建了两个大约7M的对象
 * 以下参数为运行设置中的VM Arguments参数
 * -verbose:gc
 * -XX:+PrintGCDetails
 * -Xms20M 
 * -Xmx20M
 * -Xmn10M
 * @author qianl
 *
 */
public class Test {

	public static int _1M = 1024 * 1024;

	
	public static void main(String[] args) throws InterruptedException {
		byte[] b1,b2;
		b1 = new byte[7 * _1M];
		b2 = new byte[7 * _1M];
	}

}

控制台输出为:

从控制台输出的信息,可以看出,当第一个对象b1创建了一个7M对象时,首先会考虑到新生代的eden区,如果空间够,就会放置在此,可以看出上面的eden差不多刚好放下7M的对象,使用率占了99%。
当下面的b2创建时,发现eden区域不够了,这是,Java虚拟机就会把对象放置到老年代区域中,从上面可以看到,PSOldGen使用率为70%。

故,从这个实验,可以得出结论,对象优先在eden区存放,如果eden区域空间不够,就是放置在老年代区域中。如果两个都不够,将报错:java.lang.OutOfMemoryError: Java heap space

下面,咱们來验证长期存活的对象,将进入老年代。

什么才算是长期存货的对象呢?在Java虚拟机中,给每个对象定义了一个对象年龄计数器,如果对象在eden出生并经过GC后仍然存活,并能被Survivor容纳,被移动到Survivor空间中,那么它的年龄就加1.当年龄到一定程度(默认为15岁)时,就会被移到老年代中。其中,晋升年龄的年龄,可以通过 -XX:MaxTenuringThreshold 來设置,下面,我们通过设置它为1,來做这个实验。如下代码所示:

/**
 * 以下参数为运行设置中的VM Arguments参数
 * -verbose:gc
 * -XX:+PrintGCDetails
 * -Xms20M 
 * -Xmx20M
 * -Xmn10M
 * -XX:MaxTenuringThreshold=1
 * @author qianl
 *
 */
public class Test {

	public static int _1M = 1024 * 1024;

	
	public static void main(String[] args) throws InterruptedException {
		byte[] b1,b2;
		b1 = new byte[2 * _1M];
		b2 = new byte[2 * _1M];
		b2 = null;
		System.gc(); //使b2其经过一次GC操作
		b2 = new byte[2 * _1M]; //年龄长为1,将近入老年代区域
	}

}

控制台输出:

上述第一句Full GC...说明经过一次GC操作。
由控制台的信息,可以看到PSOldGen使用了2164K,这是由于我们将年龄判断值设为1,上面程序中,b2经过我们手动操作,年龄变为了1,于是移动到了老年代中。大家可以自己将-XX:MaxTenuringThreshold设置大些,或者不设置,看PSOldGen区域会不会被使用,本人已做过实验,证明是正确的,大家可以自己做一下。

实际上,还有一种情况,Java虚拟机会动态判定对象年龄。
如果在Survivor空间中,相同年龄的所有对象大小总和,大于Survivor空间的一半,大于或等于这个年龄的对象,就可以直接进入老年代。这个,大家也可以自行下去做下实验验证。


分享到:
评论

相关推荐

    Java图书管理系统(源码)

    Java图书管理系统是一个基于Java编程语言实现的信息管理应用,主要用于图书馆的日常运营,包括图书的入库、借阅、归还、查询等操作。本系统配备有完整的数据库文件和源代码,为学习者或开发者提供了深入理解Java后端...

    操作系统(内存管理)

    在很多脚本语言中,您不必担心内存是如何管理的,这并不能使得内存管理的重要性有一点点降低。对实际编程来说,理解您的内存管理器的能力与局限性至关重要。在大部分系统语言中,比如 C 和 C++,您必须进行内存管理...

    java开源包101

    MyBatchFramework 是一个开源的轻量级的用以创建可靠的易管理的批量作业的Java包,主要特点是多线程、调度、JMX管理和批量执行报表,执行历史等。 SIP协议包 jSIP.tar jSIP这个Java包目标是用Java实现SIP(SIP:...

    Java联想(中文)

    Java自动管理内存,通过垃圾回收器(Garbage Collector)自动回收不再使用的对象所占用的内存。 四、集合框架 Java集合框架包括接口(如List, Set, Map)和实现这些接口的类(如ArrayList, HashSet, HashMap)。...

    Java虚拟机规范(Java SE 7)-完整目录书签文字版

    Java SE 7优化了栈内存管理,提升了性能。 6. 本地方法栈(Native Method Stack):支持Java调用本地(C/C++)方法。 7. 程序计数器(Program Counter Register):记录当前线程正在执行的字节码指令的地址。 ...

    JAVA在计算机软件开发中的应用研究.pdf

    - 安全性:JAVA的内存管理机制避免了指针操作带来的安全隐患,使得程序更不容易受到病毒的影响。 - 面向对象:JAVA支持面向对象编程,允许开发者创建和管理复杂的数据结构,提高代码的可读性和可维护性。 - 可移植性...

    基于ARM的嵌入式JAVA虚拟机研究与实现.pdf

    总结起来,基于ARM的嵌入式Jikes RVM研究与实现是一个旨在克服平台限制、提高性能并推动Java虚拟机技术发展的项目。通过这样的工作,我们可以期待在嵌入式系统中看到更加高效、稳定的Java运行环境,进一步促进Java在...

    基于java的开发源码-Visualvm 基于JAVA的CPU硬件资源管理器源程序.zip

    《深入理解Java CPU资源管理:VisualVM源代码分析》 VisualVM是一款强大的Java性能分析工具,它由Oracle公司提供,是Java开发者进行性能调优的重要助手。本资料包含的源码是VisualVM针对Java应用程序的CPU硬件资源...

    java3D游戏编程源代码

    7. **性能优化**: 3D游戏需要高性能的图形渲染,因此开发者需要考虑内存管理、多线程和GPU优化等技术,确保游戏流畅运行。 8. **网络编程**:如果游戏是多人在线的,那么网络编程就至关重要。Java提供Socket编程...

    Java 获取区域号段

    总结起来,"Java 获取区域号段"涉及从数据源获取并处理区域号段信息,然后在Java程序中实现查询功能。这可能需要用到第三方库,如Google的libphonenumber,以及处理和存储数据的技巧。提供的JAR文件可能包含实现这些...

    Java小程序源码

    例如,使用面向对象的设计模式,实现模块化的代码结构,以及优化性能的方法,如减少不必要的计算和提高内存管理效率。 总的来说,这个Java小程序源代码合集是一份极好的学习资源,不仅能让初学者在实践中巩固基础...

    基于Java语言的安卓软件开发研究.pdf

    基于Java语言的安卓软件开发研究主要探讨了利用Java语言进行安卓手机应用开发的相关技术要点,包括面向对象编程、系统封装、安全性与可靠性以及安卓软件架构等多个方面。以下是对该文件内容的知识点详细说明: Java...

    JAVA与VC混合编程

    JAVA的垃圾回收机制也使得内存管理变得更加便捷。然而,对于需要高性能计算或底层硬件交互的场景,JAVA可能略显不足。 VC++是Microsoft开发的一种集成开发环境,主要用于C++编程。C++是一种强大的系统级编程语言,...

    大模型部署-基于Java+多GPU实现LLaMA2推理部署-附项目源码-优质项目实战.zip

    首先,LLaMA2(Large Language Model with Multimodal Abilities 2)是现代AI研究中的一个先进模型,它具备了处理多种模态数据的能力,如文本、图像和音频。这种模型通常在大规模数据集上训练,能完成复杂的任务,如...

    基于Java的源码-jsp生产管理系统.zip

    本项目"基于Java的源码-jsp生产管理系统"旨在提供一个全面的、可定制的生产管理解决方案,它利用了Java的强大功能和JSP的易用性,为企业的生产流程提供了自动化和信息化的支持。 【系统架构】 该系统可能基于MVC...

    对对碰游戏+代码(java)

    在这个项目中,开发者使用Java语言来实现了一个经典的对对碰游戏逻辑,让我们一起来深入探讨这个项目的知识点。 1. **Java语言基础**:作为游戏的开发语言,Java以其跨平台性、面向对象特性和丰富的类库成为开发者...

    java 开发的网页爬虫

    Java开发的网页爬虫是一种利用编程技术自动化抓取互联网上信息的工具,主要应用于数据分析、搜索引擎索引、市场研究等领域。在Java中实现网页爬虫,通常涉及到以下几个关键知识点: 1. **网络请求库**:Java中常用...

    JAVA in embedded linux system

    通过深入研究Java的历史背景、关键概念以及特性,我们可以更好地理解Java如何适配于资源受限的嵌入式环境,并发挥其独特的优势。 #### Java历史 Java自1995年由Sun Microsystems发布以来,已经成为一种广泛使用的...

    java_test2

    标题“java_test2”暗示了这是一个关于Java编程的测试或示例项目,可能包含了用于学习或测试特定Java概念的代码。描述中提到的"structrue_at.csv"可能是一个数据文件,用于存储结构化数据,而"xmlfind.java"则是一个...

Global site tag (gtag.js) - Google Analytics