1.java程序的执行过程

     java源文件->解析器->class文件->java类加载器->java运行时数据区->执行引擎

2.我们接下来看一下java运行时数据区

     包含程序计数器,虚拟机栈,本地方法栈,方法区,堆,其中程序计数器,虚拟机栈,本地方法区属于指令,方法区和堆属于数据。

 一、程序计数器

       用来指示程序执行哪一条指令,这跟汇编语言的程序计数器的功能在逻辑上是一样的。JVM规范中规定,如果线程执行的是非native方法,则程序计数器指向的是当前线程正在执行的字节码指令的地址和行号,如果线程执行的是native方法,则程序计数器中的值undefined。每个线程都有自己独立的程序计数器。为什么呢?因为多线程下,一个CPU内核同一时间只会执行一条线程中的指令,因此为了使每个线程在线程切换之后能够恢复到切换之前的程序执行的位置,所以每个线程都有自己独立的程序计数器。

二、Java虚拟机栈(VM Stack)

     java虚拟机栈中存放的是一个个栈帧,栈是一种数据结构,数据结构是用来存放数据的,所以虚拟机栈也是用来存放数据的。存储当前线程运行方法是所需要的  数据,指令和返回地址。当程序执行一个方法时,就会创建一个栈帧并压入栈中,执行完毕,则会从栈帧中移除栈。虚拟机栈中有:局部变量表,操作数栈,动态链接,方法出口。

局部变量表:

存放局部变量的表,java的基本的数据类型(boolean、byte、char、short、int、float、long、double),对象的引用(reference类型,它不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址),其中64位长度的long和double类型的数据会占用2个局部变量空间(Slot),其余的数据类型只占用1个。局部变量表的大小在编译器就可以确定其大小了,因此在程序执行期间局部变量表的大小是不会改变的。在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

操作数栈:

虚拟机把操作数栈作为它的工作区,程序中的所有计算过程都是在借助于操作数栈来完成的,大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈。

       动态连接:
         每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用(指向运行时常量池:在方法执行的过程中有可能需要用到类中的常量,持有这个引用是为了支持方法调用过程中的动态连接.
      方法返回地址:
    当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。
      本地方法栈(Native Method Stack):
      本地方法栈与虚拟机栈所发挥的作用是非常相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则 为虚拟机使用到的Native方法服务。与虚拟机栈一样,本地方法栈区域也会抛出StackOverflowError和OutOfMemoryError异常。
三、方法区(Method Area):
          方法区与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、以及编译器编译后的代码等。运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。在JVM规范中,没有强制要求方法区必须实现垃圾回收。很多人习惯将方法区称为“永久代”,是因为HotSpot虚拟机以永久代来实现方法区,从而JVM的垃圾收集器可以像管理堆区一样管理这部分区域,从而不需要专门为这部分设计垃圾回收机制。不过自从JDK7之后,Hotspot虚拟机便将运行时常量池从永久代移除了。
 四、堆(Heap):
     在C语言中,程序员可以通过malloc函数和free函数在堆上申请和释放空间。那么在Java中是怎么样的呢?Java中的堆是用来存储对象本身的以及数组(当然,数组引用是存放在Java栈中的),几乎所有的对象实例都在这里分配内存。在Java中,程序员基本不用去关心空间释放的问题,Java的垃圾回收机制会自动进行处理。另外,堆是被所有线程共享的,在JVM中只有一个堆。
五、内存管理:

JVM将内存划分为6个部分:PC寄存器(也叫程序计数器)、虚拟机栈、堆、方法区、运行时常量池、本地方法栈

  • PC寄存器(程序计数器):用于记录当前线程运行时的位置,每一个线程都有一个独立的程序计数器,线程的阻塞、恢复、挂起等一系列操作都需要程序计数器的参与,因此必须是线程私有的。

  • java 虚拟机栈:在创建线程时创建的,用来存储栈帧,因此也是线程私有的。java程序中的方法在执行时,会创建一个栈帧,用于存储方法运行时的临时数据和中间结果,包括局部变量表、操作数栈、动态链接、方法出口等信息。这些栈帧就存储在栈中。如果栈深度大于虚拟机允许的最大深度,则抛出StackOverflowError异常。

    • 局部变量表:方法的局部变量列表,在编译时就写入了class文件
    • 操作数栈:int x = 1; 就需要将 1 压入操作数栈,再将 1 赋值给变量x
  • java堆:java堆被所有线程共享,堆的主要作用就是存储对象。如果堆空间不够,但扩展时又不能申请到足够的内存时,则抛出OutOfMemoryError异常。

    • 方法区:方发区被各个线程共享,用于存储静态变量、运行时常量池等信息。

    • 本地方法栈:本地方法栈的主要作用就是支持native方法,比如在java中调用C/C++

、垃圾回收机制:

 

      

    (2)、可达性分析

设立若干根对象(GC Root),每个对象都是一个子节点,当一个对象找不到根时,就认为该对象不可达。

    3、怎么回收?

  • 标记——清除算法
  • 复制算法
  • 分代算法

      (1)、标记——清除算法

遍历所有的GC Root,分别标记处可达的对象和不可达的对象,然后将不可达的对象回收。

缺点是:效率低、回收得到的空间不连续

      (2)、复制算法

将内存分为两块,每次只使用一块。当这一块内存满了,就将还存活的对象复制到另一块上,并且严格按照内存地址排列,然后把已使用的那块内存统一回   收。

优点是:能够得到连续的内存空间 
       缺点是:浪费了一半内存

      (3)、分代算法

在java中,把内存中的对象按生命长短分为:

  • 新生代:活不了多久就go die 了,比如局部变量
  • 老年代:老不死的,活的久但也会go die,比如一些生命周期长的对象
  • 永久代:千年王八万年龟,不死,比如加载的class信息
  • 有一点需要注意:新生代和老年代存储在java虚拟机堆上 ;永久代存储在方法区上

补充:java finalize()方法:

在被GC回收前,可以做一些操作,比如释放资源。有点像析构函数,但是一个对象只能调用一次finalize()方法。

深入了解Java虚拟机和内存管理的更多相关文章

  1. 深入java虚拟机学习 -- 内存管理机制

    前面说过了类的加载机制,里面讲到了类的初始化中时用到了一部分内存管理的知识,这里让我们来看下Java虚拟机是如何管理内存的. 先让我们来看张图 有些文章中对线程隔离区还称之为线程独占区,其实是一个意思 ...

  2. Java虚拟机的内存管理

    众所周知,Java程序员写的代码是没有办法控制Java对象的内存释放的,完全有JVM暗箱操作. 虽然程序员把内存的释放的任务都交给了Java虚拟机,但是并不代表Java程序就不存在内存泄漏. 反而,某 ...

  3. java虚拟机(一)——内存管理机制与OOM异常

    一  java内存区域与内存溢出异常(OOM) 1)运行时数据区域划分        1.程序计数器(Program Conuter Register) 程序计数器是一块较小的内存空间,它是当前线程执 ...

  4. [深入理解Java虚拟机]<自动内存管理>

    Overview 走近Java:介绍Java发展史 第二部分:自动内存管理机制 程序员把内存控制的权利交给了Java虚拟机,从而可以在编码时享受自动内存管理.但另一方面一旦出现内存泄漏和溢出等问题,就 ...

  5. 深入理解JAVA虚拟机 自动内存管理机制

    运行时数据区域 其中右侧三个一起的部分是每个线程一份,左侧两个是所有线程共享的. 程序计数器(Program Counter Register) 英文名称叫Program Counter Regist ...

  6. Java虚拟机理解-内存管理

    运行时数据区域 jdk 1.8之前与之后的内存模型有差异,方法区有变化(https://cloud.tencent.com/developer/article/1470519). java的内存数据区 ...

  7. 深入理解java虚拟机,内存管理部分

    1,对象回收前会调用finalize()方法,尝试自救,只能调用一次 2,上面横向对比c++的析构函数,但是java有良好的内存管理,而且try/catch做得比较好 3,回收一个常量,1,对象的实例 ...

  8. Java虚拟机的内存管理----垃圾收集器

    1.Serial收集器 优点,是简单而高效,单线程避免了线程交互的开销. 缺点,进行垃圾回收时需要Stop the world(暂停所有用户线程). 2.ParNew收集器 它是Serial收集器的多 ...

  9. Java虚拟机之内存区域

    原创文章,转载请标明出处! 目录 一.背景 二.运行时内存区域概述 1.官方描述 2.中文翻译 3.内存区域简述 4.运行时数据区简图 5.运行时数据区详图 三.JVM线程 JVM数据区域与线程关系 ...

随机推荐

  1. 日推20单词 Day03

    1.occur v. 发生,发现 2.harvest n.收获,丰收 vt.收割,得到 3.crop n.庄稼,收成 4.yield n.产量 v.产出,屈服 5.field n.田野 6.featu ...

  2. Android智能手机上的音频浅析

    手机可以说是现在人日常生活中最离不开的电子设备了.它自诞生以来,从模拟的发展到数字的,从1G发展到目前的4G以及不久将来的5G,从最初的只有唯一的功能(打电话)发展到目前的全功能,从功能机(featu ...

  3. Maven使用本地jar包(两种方式)

    有些项目会用到一些Maven库上没有的jar包,这就需要我们自己引入了 这种情况有两种办法: 第一种方式,在pom文件中引用时使用本地路径: 首先把jar包放到项目中: 然后在pom文件中引入: &l ...

  4. jacascript JSON对象的学习

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! JSON (javascript object notation) 全称是 javascript 对象表示 ...

  5. rem ~~ 你懂了吗?

    前端 开发的适配中 rem 有着举足轻重的位置,用好了,你就是神,用不好 ,直接GG:不好懵懵懂懂,要头头是道. 言归正传: 首先我们需要了解,css 布局的单位常用的有一下几种: 1.px (pix ...

  6. [LeetCode] Decode Ways II 解码方法之二

    A message containing letters from A-Z is being encoded to numbers using the following mapping way: ' ...

  7. 在iview的Table中添加Select(render)

    首先对Render进行分析,在iview官方的文档中,找到了table插入Button的例子: { title: 'Action', key: 'action', width: 150, align: ...

  8. 实验吧_密码忘记了(vim编辑器+代码审计)&天网管理系统(php弱比较+反序列化)

    密码忘记了 一开始尝试了各种注入发现都无效,在网页源码中找到了admin 的地址,输入地址栏发现并没有什么有用的信息,随便输个邮箱,网页返回了一个地址 ./step2.php?email=youmai ...

  9. [HAOI 2006]旅行comf

    Description 题库链接 给你一个 \(n\) 个点, \(m\) 条边的无向图.并给出一个点对 \((s,t)\) ,求 \(s,t\) 间的一条路径,使得路径上最大边和最小边的比值最小. ...

  10. [HNOI2003]消防局的设立

    题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状 ...