`

《分布式JAVA应用 基础与实践》 第三章 3.2 JVM内存管理(一)

阅读更多

3.2  JVM内存管理

Java不需要开发人员来显式分配内存和回收内存,而是由JVM来自动管理内存的分配及回收(又称为垃圾回收、Garbage Collection或GC),这对开发人员来说确实大大降低了编写程序的难度,但副作用可能是在不知不觉中浪费了很多内存,导致JVM花费很多时间进行 内存的回收。另外还可能会带来的副作用是由于不清楚JVM内存的分配和回收机制,造成内存泄露,最终导致JVM内存不够用。因此对于Java开发人员而 言,不能因为JVM自动内存管理就不掌握内存分配和回收的知识了。

除了内存的分配及回收外,还须掌握跟踪分析JVM内存的使用状况,以便更加准确地判断程序的运行状况及进行性能的调优。

3.2.1  内存空间

Sun JDK在实现时遵照JVM规范,将内存空间划分为方法区、堆、本地方法栈、PC寄存器及JVM方法栈,如图3.7所示。

 
图3.7  JVM内存结构

方法区

方法区存放了要加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开 发人员在程序中通过Class对象的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域。方法区域也是全局共享的,在 一定条件下它也会被GC,当方法区域要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。

在Sun JDK中这块区域对应Permanet Generation,又称为持久代,默认最小值为16MB,最大值为64MB,可通过-XX:PermSize及-XX:MaxPermSize来指定最小值和最大值。

堆用于存储对象实例及数组值,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中对象所占用的内存由GC进行回收,在32位 操作系统上最大为2GB,在64位操作系统上则没有限制,其大小可通过-Xms和-Xmx来控制,-Xms为JVM启动时申请的最小Heap内存,默认为 物理内存的1/64但小于1GB;-Xmx为JVM可申请的最大Heap内存,默认为物理内存的1/4但小于1GB,默认当空余堆内存小于40% 时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRatio=来指定这个比例;当空余堆内存大于70%时,JVM会 减小Heap的大小到-Xms指定的大小,可通过-XX:MaxHeapFreeRatio=来指定这个比例,对于运行系统而言,为避免在运行时频繁调整 Heap 的大小,通常将-Xms和-Xmx的值设成一样。

为了让内存回收更加高效,Sun JDK从1.2开始对堆采用了分代管理的方式,如图3.8所示。

 
图3.8  Sun JDK堆的分代

1. 新生代(New Generation)

大多数情况下Java程序中新建的对象都从新生代分配内存,新生代由Eden Space和两块相同大小的Survivor Space(通常又称为S0和S1或From和To)构成,可通过-Xmn参数来指定新生代的大小,也可通过-XX:SurvivorRatio来调整 Eden Space及Survivor Space的大小。不同的GC方式会以不同的方式按此值来划分Eden Space和Survivor Space,有些GC方式还会根据运行状况来动态调整Eden、S0、S1的大小。

2. 旧生代(Old Generation或Tenuring Generation)

用于存放新生代中经过多次垃圾回收仍然存活的对象,例如缓存对象,新建的对象也有可能在旧生代上直接分配内存。主要有两种状况(由不同的GC实现来 决定):一种为大对象,可通过在启动参数上设置-XX:PretenureSizeThreshold=1024(单位为字节,默认值为0)来代表当对象 超过多大时就不在新生代分配,而是直接在旧生代分配,此参数在新生代采用Parallel Scavenge GC时无效,Parallel Scavenge GC会根据运行状况决定什么对象直接在旧生代上分配内存;另一种为大的数组对象,且数组中无引用外部对象。

旧生代所占用的内存大小为-Xmx对应的值减去-Xmn对应的值。

本地方法栈

本地方法栈用于支持native方法的执行,存储了每个native方法调用的状态,在Sun JDK的实现中本地方法栈和JVM方法栈是同一个。

PC寄存器和JVM方法栈

每个线程均会创建PC寄存器和JVM方法栈, PC寄存器占用的可能为CPU寄存器或操作系统内存,JVM方法栈占用的为操作系统内存,JVM方法栈为线程私有,其在内存分配上非常高效。当方法运行完毕时,其对应的栈帧所占用的内存也会自动释放。

当JVM方法栈空间不足时,会抛出StackOverflowError的错误,在Sun JDK中可以通过-Xss来指定其大小,例如如下代码:

new Thread(new Runnable(){ 
            public void run() { 
                loop(0); 
            } 

            private void loop (int i){ 
                if(i!=1000){ 
                    i++; 
loop (i); 
                } 
                else{ 
                    return; 
                } 
            } 
}).start();  

当JVM参数设置为-Xss1K时,运行后报出类似下面的错误:

Exception in thread "Thread-0" java.lang.StackOverflowError 

 

 

Java对象所占用的内存主要从堆上进行分配,堆是所有线程共享的,因此在堆上分配内存时需要进行加锁,这导致了创建对象开销比较大。当堆上空间不足时,会触发GC,如果GC后空间仍然不足,则抛出OutOfMemory错误信息。

Sun JDK为了提升内存分配的效率,会为每个新创建的线程在新生代的Eden Space上分配一块独立的空间,这块空间称为TLAB(Thread Local Allocation Buffer),其大小由JVM根据运行情况计算而得,可通过-XX:TLABWasteTargetPercent来设置TLAB可占用的Eden Space的百分比,默认值为1%。JVM将根据这个比率、线程数量及线程是否频繁分配对象来给每个线程分配合适大小的TLAB空间 。在TLAB上分配内存时不需要加锁,因此JVM在给线程中的对象分配内存时会尽量在TLAB上分配,如果对象过大或TLAB空间已用完,则仍然在堆上进 行分配。因此在编写Java程序时,通常多个小的对象比大的对象分配起来更加高效,可通过在启动参数上增加-XX:+PrintTLAB来查看TLAB空 间的使用情况 。

在分配细节上取决于GC的实现,后续GC的实现章节会继续介绍。

除了从堆上分配及从TLAB上分配外,还有一种是基于逃逸分析直接在栈上进行分配的方式,此方式已在前文中提及。

 

分享到:
评论

相关推荐

    构建高性能的大型分布式java应用

    #### 第一章:分布式Java应用 **1.1 基于消息方式实现系统间通讯** 在分布式Java应用中,基于消息方式进行系统间通讯是一种常见的策略。这种方式的核心在于系统之间的交互是通过发送消息来完成的,这些消息可以是...

    java基础知识技术

    Java的设计初衷是为了满足分布式计算的需求,特别是互联网的应用。Java语言的主要特点包括: - **平台独立性**:Java代码可以在任何安装了Java虚拟机(JVM)的平台上运行,这得益于其“一次编写,到处运行”的设计...

    JAVA基础入门教程

    Java语言起源于Sun Microsystems公司的Green项目,最初的目的是为了开发一套适用于家用电器的分布式代码系统,以便实现设备间的互联与控制。起初项目团队考虑使用C++作为开发语言,但由于C++过于复杂且安全性不足,...

    [网盘]大型网站系统与java中间件实践 pdf下载 高清完整版

    根据提供的文件信息,本文将围绕“大型网站系统与Java中间件实践”这一主题进行深入探讨。主要内容包括:大型网站系统的架构特点、Java中间件的概念及其在大型网站中的应用实践。 ### 一、大型网站系统概述 #### ...

    Java基础教程

    - **1996年3月**:Sun公司推出了JavaWorkShop,这是一个集成开发环境(IDE),帮助开发者更高效地编写Java应用程序。 - **1996年4月**:包括Microsoft、Apple在内的更多公司获得Java许可证,进一步推动了Java技术的...

    04747 Java程序设计(一) 自考 考点 大纲(自己总结)

    #### 第三章:面向对象编程基础 **3.1 面向对象的基本概念** - 面向对象编程(OOP)是Java的核心特性之一,主要包括封装、继承和多态。 **3.2 Java类和对象** - **类**:定义了一组对象的属性和行为。 - **对象**:...

    java习题参考答案

    ### Java习题参考答案知识点解析 #### 一、Java的特点 **1.1 简单性** - **特点说明**: Java设计时...以上知识点涵盖了Java语言的基础特性和编程实践中的重要概念,有助于读者更好地理解和掌握Java编程的核心要点。

    java2参考大全(第四版)

    通过深入了解Java的起源、发展历程和技术细节,我们可以更好地掌握这门语言的核心概念和实践应用。Java不仅是一门编程语言,也是一种文化现象,它的发展历程和社区支持为后来的编程语言树立了典范。

    Java2参考大全(第四版)

    - **Android应用开发**:Java是Android平台的官方开发语言之一,拥有庞大的开发者社区和丰富的第三方库支持。 **3.3 大数据处理** - **分布式计算**:Java因其良好的性能和稳定性,在大数据处理和分布式计算领域也...

    4747 Java语言程序设计(一)

    #### 第三章 面向对象编程基础 **3.1 面向对象技术及其优点** - **面向对象技术**:一种软件开发方法论,基于对象的概念组织程序。 - **优点**: - 提高代码复用性。 - 提升代码可维护性。 - 更好地模拟现实...

    JavaEE_tutorialFromOracle

    EJB 是Java EE中的一个重要组成部分,用于构建分布式、可移植的企业级应用。EJB 包括三种类型:Session Beans、Entity Beans 和Message-Driven Beans。 - **Session Beans**:用于实现业务逻辑。 - **Entity Beans*...

    JAVA基础教程

    #### 第三部分:Java程序应用 **3.1 JAVA多线程机制** - **多线程**:并发执行多个任务。 - **实现方式**:继承`Thread`类或实现`Runnable`接口。 - 示例: ```java public class MyThread implements Runnable...

    AKKA (java) 精讲

    启动 Akka 应用程序的第一步是创建一个 Actor 系统(`ActorSystem`),这是 Akka 中所有 Actors 的容器。接下来,可以通过定义 Actor 类并创建实例来启动 Actor。Actor 可以发送消息给其他 Actor 或者自身,并通过 `...

    websphere 文档

    - **兼容性提升**:增强了与其他 IBM 产品及第三方软件的集成能力。 #### 三、WAS 系统管理概览 ##### 3.1 WAS 配置和管理架构 WAS V8.5 支持两种主要的管理架构:独立服务器环境和分布式环境。每种架构都有其...

    Java入门学习笔记

    - **分布式:** Java提供了强大的网络功能,使得开发分布式应用变得容易。 - **健壮性:** Java设计了许多机制来提高程序的健壮性和可靠性,如自动垃圾回收。 - **安全性:** Java具有严格的安全控制,可以在网络...

    JINI核心技术

    第3章 Jini模型 31 3.1 Jini设计的中心 31 3.1.1 简明性 31 3.1.2 可靠性 31 3.1.3 可伸缩性 32 3.2 设备不可知论 33 3.3 Jini不是什么 33 3.3.1 Jini不是名字服务器 33 3.3.2 Jini不是JavaBeans 34 3.3.3 Jini不是...

Global site tag (gtag.js) - Google Analytics