最近在读周志明的《深入理解Java虚拟机:JVM高级特性与最佳实践》,从中学到了很多,有些人可能会问为什么我们要学习JVM,他有什么用?在这里我想说一下,并不是这本书是大家都推荐的说有用处,我们才去读,不要人云亦云,别人说什么我们才去做什么,我们要有自己的选择,知其然还要知其所以然,不然你很是生涩的一头扎进去学习JVM,这样效果并不好,首先要了解一下jvm可以带给我们什么:

如果你这辈子只甘心做一个平庸的Java码农,那么你完全没有必要去学习JVM相关的知识,学习JVM对于一个Java程序员的好处大概可以概括为下几点:

  1. 你可以知道java程序是怎么运行的;
  2. 了解底层的东西,而不是停留在代码层面的,可以了解一下堆,栈,方法区,本地方法栈,程序计数器,垃圾回收,类加载机制,字节码指令等等;
  3. 了解底层,可以对Java有更深的理解;
  4. ....

好了,下边先来说一下jvm内存模型:

堆区(heap):

堆中存储的是对象,JVM只有一个堆,堆区是JVM内存管理中最大的一块,也是GC主要工作区域,是线程共享的。堆区的主要作用是存储对象实例,一般来说,所有的对象都在堆上分配内存。

堆的大小可以通过-Xms(最小值)和-Xmx(最大值)参数设置,-Xms为JVM启动时申请的最小内存,默认为操作系统物理内存的1/64但小于1G,-Xmx为JVM可申请的最大内存,默认为物理内存的1/4但小于1G,默认当空余堆内存小于40%时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRation=来指定这个比列;当空余堆内存大于70%时,JVM会减小heap的大小到-Xms指定的大小,可通过XX:MaxHeapFreeRation=来指定这个比列,对于运行系统,为避免在运行时频繁调整Heap的大小,通常-Xms与-Xmx的值设成一样。

栈(stack):

Java栈是与每一个线程关联的,JVM在创建每一个线程的时候,会分配一定的栈空间给线程。存储局部变量、引用、方法、返回值等。
StackOverflowError:如果在线程执行的过程中,栈空间不够用,那么JVM就会抛出此异常,这种情况一般是死循环,不合理的递归,该释放的资源没有释放造成的。

方法区:

JVM方法区又称静态区,存放所有的class和静态变量、final常量。方法区是系统分配的一个内存逻辑区域,是用来存储类型信息的(类型信息可理解为类的描述信息)。方法区主要有以下几个特点: 
      一.方法区是线程安全的。由于所有的线程都共享方法区,所以,方法区里的数据访问必须被设计成线程安全的。例如,假如同时有两个线程都企图访问方法区中的同一个类,而这个类还没有被装入JVM,那么只允许一个线程去装载它,而其它线程必须等待 
     二.方法区的大小不必是固定的,JVM可根据应用需要动态调整。同时,方法区也不一定是连续的,方法区可以在一个堆(甚至是JVM自己的堆)中自由分配。 
     三.方法区也可被垃圾收集,当某个类不在被使用(不可触及)时,JVM将卸载这个类,进行垃圾收集

本地方法栈:

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

与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。

程序计数器:

程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

由于Java 虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

如果线程正在执行的是一个Java 方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Natvie 方法,这个计数器值则为空(Undefined)。

ok,jvm内存大致分为这五个区域,下边来对一些其他知识进行一些补充:

堆栈对比:

经常有人把Java 内存区分为堆内存(Heap)和栈内存(Stack),这种分法比较粗糙,Java内存区域的划分实际上远比这复杂。这种划分方式的流行只能说明大多数程序员最关注的、与对象内存分配关系最密切的内存区域是这两块。

堆很灵活,但是不安全。对于对象,我们要动态地创建、销毁,不能说后创建的对象没有销毁,先前创建的对象就不能销毁,那样的话我们的程序就寸步难行,所以Java中用堆来存储对象。而一旦堆中的对象被销毁,我们继续引用这个对象的话,就会出现著名的 NullPointerException,这就是堆的缺点——错误的引用逻辑只有在运行时才会被发现。

栈不灵活,但是很严格,是安全的,易于管理。因为只要上面的引用没有销毁,下面引用就一定还在,在大部分程序中,都是先定义的变量、引用先进栈,后定义的后进栈,同时,区块内部的变量、引用在进入区块时压栈,区块结束时出栈,理解了这种机制,我们就可以很方便地理解各种编程语言的作用域的概念了,同时这也是栈的优点——错误的引用逻辑在编译时就可以被发现。

堆--用来存放 new 出来的对象实例,所有线程共享。

栈--主要存放引用和基本数据类型,私有线程空间。

内存泄漏和内存溢出:

内存泄露 memory leak:是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积的多了,不断的占用内存会导致内存溢出,这是我们都不想看到的。

内存溢出 out of memory:内存溢出就是你要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。

Java 堆内存的OutOfMemoryError异常是实际应用中最常见的内存溢出异常情况。出现Java 堆内存溢出时,异常堆栈信息“java.lang.OutOfMemoryError”会跟着进一步提示“Javaheapspace”。

要解决这个区域的异常,一般的手段是首先通过内存映像分析工具(如Eclipse Memory Analyzer)对dump 出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,也就是要先分清楚到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。

如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots 的引用链。于是就能找到泄漏对象是通过怎样的路径与GC Roots 相关联并导致垃圾收集器无法自动回收它们的。掌握了泄漏对象的类型信息,以及GC Roots 引用链的信息,就可以比较准确地定位出泄漏代码的位置。

如果不存在泄漏,换句话说就是内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(-Xmx 与-Xms),与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

JAVA GC 算法

 Java GC(垃圾回收)机制是一种和垃圾回收的自动内存管理机制。GC机制对JVM中的内存进行标记,并确定哪些内存需要回收,根据一定的回收策略,自动的回收内存,保证JVM中的内存空间,防止出现内存泄露和内存溢出问题。

初学JVM的更多相关文章

  1. JVM学习总结二——垃圾回收算法

    昨天总结了JVM内存分区相关的知识,这次我们将来了解下JVM的另一个核心知识点——垃圾回收算法.这一部分其实并不太难,如果对操作系统的内存处理算法有所了解,那么这部分算法其实只看名字就能明白,两者在原 ...

  2. 转:JVM 内存初学 (堆(heap)、栈(stack)和方法区(method) )

    原文地址:JVM 内存初学 (堆(heap).栈(stack)和方法区(method) ) 博主推荐 深入浅出JVM 这本书 先了解具体的概念:JAVA的JVM的内存可分为3个区:堆(heap).栈( ...

  3. JVM初学笔记

    JVM概念 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的. ...

  4. [转]JVM 内存初学 (堆(heap)、栈(stack)和方法区(method) )

    这两天看了一下深入浅出JVM这本书,推荐给高级的java程序员去看,对你了解JAVA的底层和运行机制有比较大的帮助.废话不想讲了.入主题: 先了解具体的概念:JAVA的JVM的内存可分为3个区:堆(h ...

  5. JVM 内存初学 堆(heap)、栈(stack)和方法区(method)

    这两天看了一下深入浅出JVM这本书,推荐给高级的java程序员去看,对你了解JAVA的底层和运行机制有比较大的帮助.废话不想讲了.入主题:先了解具体的概念:JAVA的JVM的内存可分为3个区:堆(he ...

  6. JVM内存初学 堆、栈、方法区

    转自: http://www.open-open.com/lib/view/open1432200119489.html 这两天看了一下深入浅出JVM这本书,推荐给高级的java程序员去看,对你了解J ...

  7. JVM 内存初学 (堆(heap)、栈(stack)和方法区(method) )(转载)

    想想面试的时候很多会问jvm这方面的问题虽然还是菜鸟不太能用到现在但是还是了解一下, 找资料的时候看见个大佬写的很好转载到这方便以后自己复习和给大佬做宣传 以下为大佬的博客原文: 这两天看了一下深入浅 ...

  8. 转 方法区(method) )、栈区(stack)和堆区(heap)之JVM 内存初学

    JAVA的JVM的内存可分为3个区:堆(heap).栈(stack)和方法区(method) 堆区: 1.存储的全部是对象,每个对象都包含一个与之对应的class的信息.(class的目的是得到操作指 ...

  9. JVM学习(2)——技术文章里常说的堆,栈,堆栈到底是什么,从os的角度总结

    俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及到的知识点总结如下: 堆栈是栈 JVM栈和本地方法栈划分 Java中的堆,栈和c/c++中的堆,栈 数据结构层面的堆,栈 os层面 ...

随机推荐

  1. iOS 让View始终在屏幕最上层

    UIView层次管理 放到最上层 放到最下层 将一个UIView显示在最前面只需要调用其父视图的 bringSubviewToFront()方法. 将一个UIView层推送到背后只需要调用其父视图的  ...

  2. ABAP 7.4 新语法-内嵌生命和内表操作

    1.内嵌声明 2.内表操作 3.opensql ************************************************************************ 1. ...

  3. webstorm配置编译sass的输出目录

    关于这个的问题,虽说不是很难,但还是踩了点小坑,下面就来介绍下如何使用webstorm配置编译sass的输出目录. 1.下载Ruby 2.使用Ruby安装sass 3.检测是否安装成功. 前面的几步很 ...

  4. OnsenUI 前端框架(三)

    上一章咱们学习了OnsenUI的工具栏.侧边栏和标签栏.通过对页面上这三部分的学习,咱们对混合应用的一个页面有了大体上的认识.从这一章开始,咱们学习OnsenUI混合项目开发过程中会用到的各种各样的组 ...

  5. 【原创】bootstrap框架的学习 第六课[bootstrap代码]

    Bootstrap 允许您以两种方式显示代码: 第一种是 <code> 标签.如果您想要内联显示代码,那么您应该使用 <code> 标签. 第二种是 <pre> 标 ...

  6. bzoj2560 串珠子

    Description 铭铭有n个十分漂亮的珠子和若干根颜色不同的绳子.现在铭铭想用绳子把所有的珠子连接成一个整体. 现在已知所有珠子互不相同,用整数1到n编号.对于第i个珠子和第j个珠子,可以选择不 ...

  7. 实现sticky footer的五种方法

    2017-04-19 16:24:48 什么是sticky footer 如果页面内容不够长的时候,页脚块粘贴在视窗底部:如果内容足够长时,页脚块会被内容向下推送. 用position实现? 如果是用 ...

  8. Oracle GoldenGate中HANDLECOLLISIONS参数使用详解

    Oracle GoldenGate中HANDLECOLLISIONS参数使用详解   HANDLECOLLISIONS 是一个 replicat 进程参数,主要在 initial load 中使用.在 ...

  9. OC中Foundation框架之NSDictionary、NSMutableDictionary

    NSDictionary概述 NSDictionary的作用类似:通过一个key ,就能找到对应的value 同样 NSDictionary是不可变的,一旦初始化完毕,里面的内容就无法修改 NSDic ...

  10. 利用PHPExcel读取Excel的数据和导出数据到Excel

    PHPExcel是一个PHP类库,用来帮助我们简单.高效实现从Excel读取Excel的数据和导出数据到Excel.也是我们日常开发中,经常会遇到的使用场景.比如有个客户信息表,要批量导出发给同事,我 ...