1、JVM是如何管理内存的

Java中,内存管理是JVM自动进行的,无需人为干涉。

了解Java内存模型看这里:java内存模型是什么样的 
了解jvm实例结构看这里:jvm实例的结构是什么样的 
创建对象或者变量时, JVM会自动分配内存(当然这个分配是遵循严格规则的)。当JVM发现某些对象不再需要的时候,就会对该对象占用的内存进行重分配(释放)操作,而且使得分配出来的内存能够提供给所需要的对象。

在这个方面,其他一些编程语言里面,内存管理是程序员的职责,程序员是需要手动管理内存。这一点C++的程序员很清楚,最终大部分开发时间都花在了调试这种内存管理程序以及修复相关错误上。

了解显示内存管理的弊端看这里:显示内存管理有什么弊端

2、JVM内存组成结构

了解内存分配策略看这里:内存分配有哪些策略 
JVM的内存组织需要在不同的运行时数据区进行操作。包括PC寄存器(计数器 pc registers)、方法区(method area)、本地方法栈(native method stacks)、栈(stacks)、堆(heap)。如图: 

PC寄存器(计数器 pc registers) 
每个新的线程启动后,它就会被JVM在内部分配自己的PC寄存器(计数器 pc registers),通过计数器来指示下一条指令执行。

方法区(method area) 
方法区是用来储存类的装载信息的。当JVM加载一个类的时候,它定位到对应路径里去查找对应的Class文件,类加载器读取类文件(线性二进制数据),然后将该文件传递给JVM,JVM从二进制数据中提取信息并且将这些信息存储在方法区。 
在JVM内部,所有的线程共享相同的方法区。需要注意的是:类中的静态变量(类变量)就是储存在方法区中的(了解静态变量看这里:局部变量、类变量、实例变量有什么区别)。

方法区中除了有类文件信息外,还包含一个运行时常量池(Runtime Constant Pool),用来存放基本类型包装类(包装类不管理浮点型,整形只会管理-128到127)和String(通过String.intern()方法可以强制将String放入常量池)。之所以称之为动态,是因为不单能在编译期产生常量,运行期间也可以,当然运行时常量池同样是所有线程共享。(Java虚拟机对Class文件的每一部分的格式都有严格的规定,每一个字节用于存储哪种数据都必须符合规范,这样才会被虚拟机装载和执行。但对于运行时常量池,Java虚拟机规范没有做任何细节的要求,不同的提供商实现的虚拟机可以按照自己的需要来实现这个内存区域。)

由于运行时常量池是方法区的一部分,所以会受到方法区内存的限制,当常量池无法再申请到内存时会抛出OutOfMemoryError: PermGen space异常(Java8以后没有方法区,由本地元空间代替,溢出会抛出OutOfMemoryError: Metaspace异常)。

本地方法栈(native method stacks) 
若某线程正在执行一个本地Java方法,该线程的本地方法内存栈中,保存了本地Java方法调用状态,其状态包括局部变量、被调用的参数、它的返回值、以及中间计算结果。 
在这种情况下,使得这些本地方法和其他内存数据区的内容尽可能独立,而且这些本地方法执行的字节码,有可能根据操作系统环境的不同,使得其编译出来的本地字节码的结构也有一定的差异。

栈(stacks)

  1. 对于线程内存栈分配:当一个新线程启动的时候,JVM会为Java线程创建每个线程的独立内存栈。内存栈是由栈帧构成,在JVM里面,栈帧的操作只有两种:出栈和入栈。正在被线程执行的方法称为当前线程方法,而该方法的栈帧就称为当前帧,而在该方法内定义的类称为当前类。

  2. 对于方法:当一个线程调用某个Java方法时,Jvm创建并将一个新帧压入到内存栈中,这个帧成为当前栈帧,当该方法执行的时候,JVM使用内存栈来存储参数引用、局部引用变量、基本类型数值、中间计算结果以及其他相关数据。 
    方法在执行过程有可能因为两种方式而结束:如果一个方法返回,属于正常结束;如果在这个过程抛出异常而结束,为异常结束。不论是正常结束还是异常结束,JVM都会弹出或者丢弃该栈帧,则上一帧的方法就成为了当前帧。

  3. 对于线程:在JVM中,Java线程的栈数据是某个线程独有的,其他的线程不能修改或访问该线程的栈帧。当一个线程调用某个方法的时候,方法的局部变量是在线程独有的栈帧存储,只有当前线程可以访问该局部变量, 所以不用担心多线程同步访问Java的局部变量。

  4. 对于容量:编程过程,允许指定Java栈的初始大小以及最大、最小容量。

堆(heap)

    1. 对于对象内存堆分配:当一个Java程序创建一个对象或者一个数组时,JVM实例会针对该对象和数组分配一个新的内存堆空间。在JVM实例内部,只存在一个内存堆的实例,所有的依赖该JVM的Java程序都共享该实例。

    2. 对于进程内存堆分配:在Java程序启动的时候,会得到JVM分配的属于自己的堆空间,而且针对每一个Java应用程序,这些运行Java程序的堆空间都是相互独立的。

    3. 对于内存堆共享:上述两种分配并不冲突,JVM在初始化运行的时候整体堆空间只有一个,这个是Java语言平台直接从操作系统上能够拿到的整体堆空间(不会超过物理内存最大值),所以的依赖该JVM的程序都可以得到这些内存空间。但是针对每一个独立的Java程序而言,这些堆空间是相互独立的,每一个Java应用程序在运行最初都是依靠JVM来进行堆空间的分配的。

    4. 对于进程:两个相同的Java程序,在运行时处于不同的进程中(一般为java.exe),它们各自分配的堆空间都是独立的,不能相互访问。只是两个Java进程初始化拿到的堆空间都是来自JVM的分配(从最初的内存堆实例里面分配出来的)。

    5. 对于线程:在同一个Java进程中,不同的线程是可以共享每一个Java程序拿到的内存堆空间的。这也是为什么在开发多线程程序的时候,针对同一个Java程序必须考虑线程安全问题,因为在一个Java进程里,所有的线程是可以共享这个Java进程堆空间中的数据的。了解进程和线程看这里:线程和进程有什么区别

    6. 堆内存释放:JVM拥有针对新的对象分配内存的指令,但是却不包含释放该内存空间的指令。当然开发过程可以在Java源代码中显示释放内存或者说在JVM字节码中进行显示的内存释放,但是JVM仅仅只是检测堆空间中是否有引用不可达(不可以引用)的对象,然后将接下来的操作交给垃圾回收器(GC)来处理。

jvm是如何管理内存的的更多相关文章

  1. jvm是如何管理内存的 .ZT

    http://blog.csdn.net/u014421556/article/details/51744044

  2. JVM的组成部分与内存管理

    JVM的组成部分与内存管理 JVM区域划分 由于Java程序是交由JVM执行的,所以我们在谈Java内存区域划分的时候事实上是指JVM内存区域划分.在讨论JVM内存区域划分之前,先来看一下Java程序 ...

  3. JVM读书笔记之内存管理

    对于从事C.C++程序开发人员来说,在内存管理领域,他们既是拥有最高权力的“皇帝”又是从事最基础工作的“劳动人民”--既拥有每一个对象的“所有权”,又负责每一个对象生命开始到终结的维护责任. 对于Ja ...

  4. Android内存管理(11)*常见JVM回收机制「Java进程内存堆分代,JVM分代回收内存,三种垃圾回收器」

    参考: http://www.blogjava.net/rosen/archive/2010/05/21/321575.html 1,Java进程内存堆分代: 典型的JVM根据generation(代 ...

  5. 【原创】android内存管理-内存泄漏原因

    转载请注明出处 http://www.cnblogs.com/weiwangnuanyang/p/5704596.html 先讲一下内存泄漏的概念:内存泄露是指无用对象持续占有内存,或者内存得不到及时 ...

  6. Java是如何管理内存的?

    本文转自CSDN用户Kevin涂腾飞的文章java内存管理机制:http://blog.csdn.net/tutngfei1129287460/article/details/7383480 JAVA ...

  7. JVM(三)内存回收(一)

    最近花了相当长一段时间在看Hotspot JVM的GC和内存分配,本节先总结和回顾一下内存回收的相关知识点,内存的分配放到下节再讨论. 一.什么是JVM的GC GC即Garbage Collectio ...

  8. JVM体系结构-----深入理解内存结构

    一.概述 内存在计算机中占据着至关重要的地位,任何运行时的程序或者数据都需要依靠内存作为存储介质,否则程序将无法正常运行.与C和C++相比,使用Java语言编写的程序并不需要显示的为每一个对象编写对应 ...

  9. 深入理解JVM(5)——垃圾收集和内存分配策略

    1.垃圾收集对象 垃圾收集主要是针对堆和方法区进行. 程序计数器.虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后也会消失,因此不需要对这三个区域进行垃圾回收. 哪 ...

随机推荐

  1. 利用html5的画布canvas进行图片压缩处理

    在网上找的代码,按自己的需求改了下,忘记在哪找的了.这里记着方便自己以后学习. // 参数,最大高度 //var MAX_HEIGHT = 100; var MAX_WIDTH = 200; // 渲 ...

  2. C语言读取PE文件信息(一)

    接下来的内容来源于对该博客文章http://www.pediy.com/kssd/pediy06/pediy7006.htm的解析. 一.打印Sections信息.下面的程序打印出Windows_Gr ...

  3. Android 如何通过代码模拟按钮点击 延时函数

    View.performClick();   比如: private Button mButton01;    mButton01 = (Button)findViewById(R.id.myButt ...

  4. Add and Search Word

    Trie 树的一个应用 Design a data structure that supports the following two operations: void addWord(word) b ...

  5. HTTP、FTP状态码 (share)

    来源:http://www.cnblogs.com/setsail/archive/2012/03/23/2413577.html HTTP1xx - 信息提示(这些状态代码表示临时的响应.客户端在收 ...

  6. mySql中alter table的使用

    1.修改表名:alter table 原表名 rename to 新表名; 2.新增列:alter table 表名 add column 列名 varchar(20) ; 3.删除列:alter t ...

  7. ajax 选项卡

    Ajax其实就是交互式网页应用开发技术包括以下几个方面: 1.XHTML和CSS 2.使用DOM作为动态显示和交互 3.使用XML和XSLT 做数据交互和操作 (这些完全不太懂) 4.使用XMLHtt ...

  8. groupspecWidhoutAuthorizations与groupspecWidthAuthorizations的区别

    GroupSpecifier是一个用来定义group所有参数的类.首先,将它命名为“myGroup/g1”.然后设置 serverChannel与Stratus进行沟通.最后发布.这样,我们就完成了P ...

  9. angular2 - content projection-

    angular2中的内容映射: App.component: <my-day> <my-lucky> </my-lucky> </my-day> MyD ...

  10. UVa 221城市正视图(离散化)

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...