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. Maven学习笔记(1)之安装Maven

    此笔记是学习Maven时自己摸索+各种百度而来,并非全部原创,望与各位一同学习,勿拍~勿拍~ 安装步骤 1.下载Maven的最新版本,地址:http://maven.apache.org/downlo ...

  2. List转MVC DropDownListFor(SelectList)

    /// <summary> /// List转SelectListItem /// </summary> /// <typeparam name="T" ...

  3. 如何查看PYTHON Django的保存路径

    如何查看PYTHON Django的保存路径 $ python -c " import sys sys.path = sys.path[1:] import django print(dja ...

  4. G - 小希的迷宫

    Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Pract ...

  5. LintCode Implement Queue by Two Stacks

    1. stack(先进后出): pop 拿出并返回最后值: peek 返回最后值: push 加入新值在后面并返回此值. 2. queue(先进先出) : poll = remove 拿出并返第一个值 ...

  6. mybatis:Invalid bound statement (not found)

    [常规解决办法] 如果出现: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found) 一般的原因 ...

  7. 编程:递归编程解决汉诺塔问题(用java实现)

    Answer: //Li Cuiyun,October 14,2016. //用递归方法编程解决汉诺塔问题 package tutorial_3_5; import java.util.*; publ ...

  8. MVC授权

    public class CommonController : Controller { protected override void OnAuthorization(AuthorizationCo ...

  9. 在as3中使用protobuf

    在最近参与开发的adobe air项目中,前后端的通信协议从XML.JSON再到protobuf,最后选择protobuf原因,主要是前后端维护protobuf协议就行了,同时还可以利用IDE做一些编 ...

  10. 【OPENGL】第二篇 HELLO OPENGL(续)

    上一次我们在这里分析了OpenGL的例子,但是最后还少分析最重要的部分:着色器相关的代码.因此这一次作为前一篇文章的续集. 上一篇文章的地址 http://www.cnblogs.com/MyGame ...