本篇其实就是一个读书笔记,书是《深入理解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()方法)。

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

  1. JVM内存模型、指令重排、内存屏障概念解析

    在高并发模型中,无是面对物理机SMP系统模型,还是面对像JVM的虚拟机多线程并发内存模型,指令重排(编译器.运行时)和内存屏障都是非常重要的概念,因此,搞清楚这些概念和原理很重要.否则,你很难搞清楚哪 ...

  2. JVM内存模型和性能优化 转

    JVM内存模型和性能优化 JVM内存模型优点 内置基于内存的并发模型:      多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于 ...

  3. JVM内存模型和性能优化

    JVM内存模型优点 内置基于内存的并发模型:      多线程机制 同步锁Synchronization 大量线程安全型库包支持 基于内存的并发机制,粒度灵活控制,灵活度高于数据库锁. 多核并行计算模 ...

  4. JVM初探 -JVM内存模型

    JVM初探 -JVM内存模型 标签 : JVM JVM是每个Java开发每天都会接触到的东西, 其相关知识也应该是每个人都要深入了解的. 但接触了很多人发现: 或了解片面或知识体系陈旧. 因此最近抽时 ...

  5. JVM内存模型和关键参数设置

    一. JVM内存模型: Jvm内存模型是学好Java很重要的一部分,该部分学习能让我们在系统运维的时候,或者优化服务器的时候能够有方法,懂原理. 二. Jvm关键参数: 1. 堆大小设置参数: -Xm ...

  6. 记录JVM内存模型,参数含义和优化

    一.JVM内存模型 (图片来自网络) 根据Java虚拟机规范,JVM将内存划分为: New(年轻代) Tenured(年老代) Perm (永久代) 其中New和Tenured属于堆内存,堆内存会从J ...

  7. 【转】JVM内存模型

    http://longdick.iteye.com/blog/473866 图解JVM内存模型 博客分类: JVM JVM活动SUN  /** *  转载请注明作者longdick    http:/ ...

  8. jvm内存模型和内存分配

    1.什么是jvm? (1)jvm是一种用于计算设备的规范,它是一个虚构出来的机器,是通过在实际的计算机上仿真模拟各种功能实现的. (2)jvm包含一套字节码指令集,一组寄存器,一个栈,一个垃圾回收堆和 ...

  9. JVM的stack和heap,JVM内存模型,垃圾回收策略,分代收集,增量收集

    (转自:http://my.oschina.net/u/436879/blog/85478) 在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认 ...

  10. Java基础知识强化100:JVM 内存模型

    一. JVM内存模型总体架构图:  方法区和堆由所有线程共享,其他区域都是线程私有的 二. JVM内存模型的结构分析: 1. 类装载器(classLoader) 类装载器,它是在java虚拟机中用途是 ...

随机推荐

  1. 【iOS XMPP】使用XMPPFramewok(二):用户登录

    转自:http://www.cnblogs.com/dyingbleed/archive/2013/05/10/3069397.html 用户登录 准备工作 比较知名的开源XMPP服务器:一个是Ope ...

  2. Linux下找不到so文件的解决办法

    http://www.cnblogs.com/xudong-bupt/p/3698294.html 如果使用自己手动生成的动态链接库.so文件,但是这个.so文件,没有加入库文件搜索路劲中,程序运行时 ...

  3. java二维数组遍历

    数组名加上length(arr.length),表示该数组的行数(Row): 指定索引加上length(arr[x].length),表示该行的元素个数,即该行的列数(Column). public  ...

  4. Recommender Systems中Yehuda Koren 和 Ma Hao的paper

    以前读了Yehuda Koren和Ma Hao的论文,感觉非常不错,这里分享一下.如果想着具体了解他们近期发的论文,可以去DBLP去看看. Yehuda Koren也是Netflix Prize的冠军 ...

  5. 李洪强iOS经典面试题

    李洪强iOS经典面试题 1. struct和class的区别 swift中,class是引用类型,struct是值类型.值类型在传递和赋值时将进行复制,而引用类型则只会使用引用对象的一个"指 ...

  6. iOS高版本备份恢复到低版本系统的方法

    一般来说,在更新iOS系统的时候我们都会建议大家先用iTunes对系统进行完整备份.但时不时都会有人偷懒,或者使用手机OTA升级而没有对系统备份,最终导致不满意新系统了,想降级却无备份可以恢复的尴尬局 ...

  7. 比较正确的 iPhone7/7+ 的进入DFU的方法是这样的

    正确的.没有歧义的.在WIndows7系统下进入DFU并刷机的方法是: 1)PC端打开iTunes,数据线连接iPhone7与PC: 2)iPhone7关机: 3)同时按下电源键和音量减键,LOGO会 ...

  8. 关于Python中深拷贝与浅拷贝的理解(一)---概念

    import copy a = [1, 2, 3, 4, ['a', 'b']] #原始对象 b = a #赋值,传对象的引用 c = copy.copy(a) #对象拷贝,浅拷贝 d = copy. ...

  9. 04-老马jQuery教程-DOM节点操作及位置和大小

    1. jQuery创建DOM标签 1.1 DOM动态创建标签的方法 DOM时代我们通过document的createElement方法动态创建标签.创建标签后,动态的给他添加属性.例如代码: // 动 ...

  10. C#学习笔记(21)——C#获取文件夹下的所有文件的文件名

    说明(2017-7-30 23:11:59): 1. 文件处理老是忘,学的不扎实. 2. 路径用Directory,文件名用file. 3. 我也推荐用第二种方法,可以拿到文件的所有信息,比如扩展名什 ...