【1】JVM-内存模型

本篇其实就是一个读书笔记,书是《深入理解JAVA虚拟机》,在网上搜索JAVA内存,说的比较好的其实很多都源自这本书,作为一个JAVA程序员,理解虚拟机是通向高级程序员的必经道路。本篇中的图片源自当时网上,具体出处找不到了,请见谅。

所谓的线程安全,其实就是不同线程对同一个资源的访问和修改引发的数据不一致问题。

对于线程安全的理解,需要了解JVM中的内存模型。JAVA中一个线程创建的时候,JVM就会为其分配一个主内存和工作内存,每个线程都有自己的完全独立的工作内容,而主内存却是他们所共享的,那么问题来了,线程不安全就是由于共享主内存导致的。一旦多个线同时对主内存中的同一个资源进行操作,那么就可能导致资源状态的不一致。我们知道当一个线程需要和主内存进行交互的时候,数据从主内存拷贝到工作内存中,在线程实际处理的时候,数据其实是一个副本,当线程处理完了之后再去更新主内存,正是由于这种机制,故而会产生线程的安全性问题,需要对资源加锁来解决这种问题。

1、程序计数器

这是个什么鬼呢?我们都知道,CPU的计算时间是以分片的方式给到每个线程的,换句话说,所谓的并行其本质就是串行。比如线程A执行到了一部分,CPU将控制权给了线程B,那么线程A重新得到CPU的资源时,如何恢复工作呢?这个程序计数器就来帮助线程A找到其中间状态,从而恢复到正确的执行位置。程序计数器所占内存是线程私有的,同时也是Java 虚拟机规范中没有规定任何OutOfMemoryError 情况的区域。

2、JAVA虚拟机栈

它也是线程私有的,它所占有的内存空间也就是我们平时所说的“栈(stack)内存”。并且和线程的生命周期相同。虚拟机栈描述的是Java 方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame ①)用于存储局部变量表(基本数据类型,对象的引用和returnAddress类型)、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

局部变量表需要的内存在编译期间就确定了,故而方法运行期间不会改变其大小。

在Java 虚拟机规范中,对这个区域规定了两种异常状况:

a.如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError 异常;

b.如果虚拟机栈可以动态扩展(当前大部分的Java 虚拟机都可动态扩展,只不过Java 虚拟机规范中也允许固定长度        的虚拟机栈),当扩展时无法申请到足够的内存时会抛出OutOfMemoryError 异常。

3、JAVA堆

JAVA堆一般是JVM管理的内存中最大的一块,JAVA堆在主内存中,是被所有线程共享的一块内存区域,其随着JVM的创建而创建,堆内存的唯一目的是存放对象实例。同时JAVA堆也是GC管理的主要区域

如果从内存回收的角度看,由于现在收集器基本都是采用的分代收集算法,所以Java 堆中还可以细分为:新生代和老年代;再细致一点的有Eden 空间、From Survivor 空间、To Survivor 空间等。

如果从内存分配的角度看,线程共享的Java 堆中可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)。

不过,无论如何划分,都与存放内容无关,无论哪个区域,存储的都仍然是对象实例,进一步划分的目的是为了更好地回收内存,或者更快地分配内存。

如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,将会抛出OutOfMemoryError 异常。

4、本地方法栈

本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java 方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native 方法服务。虚拟机规范中对本地方法栈中的方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。甚至有的虚拟机(譬如Sun HotSpot 虚拟机)直接就把本地方法栈和虚拟机栈合二为一。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError 和OutOfMemoryError异常。

5、方法区

方法区也是各线程共享的一个内存区域。主要用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

虽然Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java 堆区分开来。

Java 虚拟机规范对这个区域的限制非常宽松,除了和Java 堆一样不需要连续的内存和可以选择固定大小或者可扩展外,还可以选择不实现垃圾收集。相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收确实是有必要的。在Sun 公司的BUG 列表中,曾出现过的若干个严重的BUG 就是由于低版本的HotSpot 虚拟机对此区域未完全回收而导致内存泄漏。

根据Java 虚拟机规范的规定,当方法区无法满足内存分配需求时,将抛出OutOfMemoryError 异常。

6、常量池

Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量表(constant_pool table),用于存放编译期已可知的常量,这部分内容将在类加载后进入方法区(永久代)存放(JDK1.7开始,常量池已经被移到了堆内存中)。但是Java语言并不要求常量一定只有编译期预置入Class的常量表的内容才能进入方法区常量池,运行期间也可将新内容放入常量池(最典型的String.intern()方法)。

时间: 2024-08-07 00:18:32

【1】JVM-内存模型的相关文章

JVM内存模型-转载

http://my.oschina.net/u/567296/blog/303780 JVM的内部结构如下图: JVM主要包括两个子系统和两个组件: 1. 两个子系统分别是Class loader子系统和Execution engine(执行引擎) 子系统: 1.1 Class loader子系统的作用:根据给定的全限定名类名(如 java.lang.Object)来装载class文件的内容到 Runtime data area中的method area(方法区域).Java程序员可以exten

jvm的stack和heap,JVM内存模型,垃圾回收策略,分代收集,增量收集(转)

深入Java虚拟机:JVM中的Stack和Heap(转自:http://www.cnblogs.com/laoyangHJ/archive/2011/08/17/gc-Stack.html) 在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认识Stack和Heap,并通过这些原理认清Java中静态方法和静态属性的问题. 一般,JVM的内存分为两部分:Stack和Heap. Stack(栈)是JVM的内存指令区.Stack管理很简单,push

JVM内存模型以及HotSpot的GC策略

概述 想要进一步掌握Java语言,必须要深入了解一下Java程序的运行环境.本文会对JVM的内存模型.Java内存自动管理机制.以及Oracle官方虚拟机HotSpot在GC方面的实现策略进行大概的梳理. 什么是Java的内存模型? 众所周知,Java程序是运行在JVM上面的,但是不具体指定是哪一款JVM,只要是符合一定的规范的JVM,都可以正确的运行Java字节码.该规范由Oracle官方提供,旨在描述一个抽象的JVM,它包含很多部分,包括class文件结构.运行时内存状态.指令集等. 而上述

jvm内存模型及分配

1.什么是jvm?(1)jvm是一种用于计算设备的规范,它是一个虚构出来的机器,是通过在实际的计算机上仿真模拟各种功能实现的.(2)jvm包含一套字节码指令集,一组寄存器,一个栈,一个垃圾回收堆和一个存储方法域.(3)JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行.JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行. 2.jdk.jre.jvm是什么关系?(1)JRE(Java

JVM内存模型理解

Java虚拟机(Java VirtualMachine 简称JVM)是运行所有Java程序的抽象计算机,是Java语言的运行环境,它是Java 最具吸引力的特性之一. JVM内存模型 1.方法区和堆是所有线程共享的数据区 1)堆:存放对象的实例 2)方法区:存放已被虚拟机加载的类信息.常量.静态变量.即时编译器编译后的代码 3)运行时常量池:是方法区的一部分,存放Class的版本.字段.方法.接口等描述信息,字符串池就是这个!!! 2.程序计数器.虚拟机栈.本地方法栈是线程隔离的数据区 4)程序

JVM内存模型及垃圾回收机制

JVM内存模型1.栈Java栈是与每一个线程关联的,JVM在创建每一个线程的时候,会分配一定的栈空间给线程.存储局部变量.引用.方法.返回值等.StackOverflowError:如果在线程执行的过程中,栈空间不够用,那么JVM就会抛出此异常,这种情况一般是死递归造成的.2.堆 Java中堆是由所有的线程共享的一块内存区域,堆用来保存各种JAVA对象,比如数组,线程对象等. 2.1堆的分代JVM堆一般分为三个部分:Young:年轻代Young区被划分为三部分,Eden区和两个大小严格相同的Su

JVM内存模型及String对象内存分配

昨天看了一篇关于<Java后端程序员1年工作经验总结>的文章,其中有一段关于String和StringBuffer的描述,对于执行结果仍然把握不准,趁此机会也总结了下JVM内存模型. 1.JVM运行时数据区域 关于JVM内存模型之前也了解过一些,也是看过就忘,好记性比如烂笔头,记下来吧.参考此文章http://chenzhou123520.iteye.com/blog/1585224 图1 JVM运行时数据区域 (1).程序计数器(Program Counter Register): 程序计数

JVM内存模型,垃圾回收算法

JVM内存模型总体架构图 程序计数器多线程时,当线程数超过CPU数量或CPU内核数量,线程之间就要根据时间片轮询抢夺CPU时间资源.因此每个线程有要有一个独立的程序计数器,记录下一条要运行的指令.线程私有的内存区域.如果执行的是JAVA方法,计数器记录正在执行的java字节码地址,如果执行的是native方法,则计数器为空.虚拟机栈线程私有的,与线程在同一时间创建.管理JAVA方法执行的内存模型.每个方法执行时都会创建一个桢栈来存储方法的的变量表.操作数栈.动态链接方法.返回值.返回地址等信息.

【转】jvm 内存模型及内存调优

一,JVM内存模型概括 还有一个寄存器,线程运行于其上面 1.程序计数器 记录线程的执行位置,线程私有内存,唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域 2.线程栈(VM stack) 栈的默认大小是1M -Xss2m 这样设置成2M 异常 :Fatal: Stack size too small 异常的引起一般是线程数目太多 3.本地方法栈(native stack) 即为一些Native方法分配的stack 异常:java.lang.OutOfMemo

JVM内存模型以及垃圾回收

原文:http://www.blogjava.net/freeman1984/archive/2011/03/08/345929.html JVM内存模型以及垃圾回收内存由 Perm 和 Heap 组成. 其中 Heap = {Old + NEW = { Eden , from, to } }具体可查看javavisualvm JVM内存模型中分两大块,一块是 NEW Generation, 另一块是Old Generation. 在New Generation中,有一个叫Eden的空间,主要是