java虚拟机深入理解

          最近在看一本书,讲的是java虚拟机相关的知识,写一篇博客来使用记录自己学习的过程,虚拟机的简介,由来,以及分类都是在网上容易找到的,所以在我想主要记录一些关于知识方面的东西。以后时间在补上这个简介的东西,这里讲的主要是是HotSpot虚拟机。

        我的第二章       java内存区域和内存溢出处理

             2.1   为啥要学习java虚拟机

                    作为一个java程序员,在虚拟机自动内存的帮助下,不需要为每一个new操作去写配对的delete/free操作,不容易出现内存泄漏和内存溢出的操作,但是一旦出现内存泄漏和溢出的问题,如果你不了解虚拟机是怎样使用内存的话,那么排查错误讲师一个异常艰难的工作

              2.2 java虚拟机运行时期的数据

                  什么都不说,先来一张图。(在网上随便一艘都可以找到这个)

                   push_thumb[23]

                  2.2.1   程序计数器

                                  概念:当前线程所执行的字节码的行号指示器。

                                  扩展概念:字节码指示器   

                                               (字节码指示器在工作的时候就是改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转和异常处理,线程恢复这些基本功能的)。

                               工作原理:通过线程轮换切换并分配处理器的执行时间来实现的。

                              内存类型:线程私有。

                                               这里简单解释一下:在任何一个时刻,一个处理器(对于多核处理器来说是一个内核)都会只执行一个线程中的指令,因此,为了线程切换后能够恢复到正确的位置,每一条线程都需要独立的程序计数器,每条线程之间计数器互不影响,独立存储。

                               记录数据类型:

                                             (1) 如果当前线程执行的是一个java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址。

                                                (2)如果正在执行的是Native方法,这个计数器则为空(unfined),

                               唯一性:唯一 一个 在java内存虚拟机规范中没有规定任何OutofMemoryError的区域。

                        2.2.2 java虚拟机栈

                                  概念:java执行方法的内存模型:每个方法在创建的时候都会创建一个栈帧(Stack Frame),用于存储 局部变量表,操作数栈,动态链栈,方法出口信息。

                                 内存类型:线程私有的。

                                声明周期:线程声明周期。

                               执行原理:每一个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

                               重要部分(必须要基础的部分):   局部变量表

                                       局部变量表:::::

                                               存放数据类型:编译时期可知的基本数据类型(byte,char,short,int,float,long,double,boolean),

                                                      对象引用(reference类型,它不等同与对象本身,可能是一个执行对象起始地址的引用指针,可以是一个代表对象的句柄或其他对此对象相关的位置)和returnAddress类型(指向一条字节码指令的地址)。

                                              重点数据类型讲解:long,double 占用两个局部变量空间(Slot),其余类型都是一个。

                                              内存空间分配时间:编译期(也就是在方法运行期间不会改变局部变量表的大小)。

                              java虚拟机栈异常:

                                                           StackOverFlowError:线程请求的栈深度大于虚拟机所允许的栈深度

                                                           OutOfMemoryError:虚拟机栈在动态扩展的时候,无法申请到足够的内存。

                       2.2.3         本地方法栈

                                          功能:和虚拟机栈类似。

                                          区别:虚拟机栈为虚拟机执行java方法(字节码)服务的。本地方法栈是虚拟机使用Nativ方法执行的服务。

                             

                                         本地方法栈栈异常:

                                                           StackOverFlowError:线程请求的栈深度大于虚拟机所允许的栈深度

                                                           OutOfMemoryError:栈在动态扩展的时候,无法申请到足够的内存。

                        2.2.4          java堆

                                          特点:java虚拟机中内存最大。

                                          内存类型:线程共享,

                                          创建时间:在虚拟机启动时

                                          目的: 存放对象实例,几乎所有的对象实例和数组(但是随着JIT的发展,也不是那么绝对了)

                                          和垃圾回收器的关系:也叫Gc堆,现在的垃圾回收算法主要是分代收集算法,

                                          分类:     新生代,老生代(还有很多,这里就不在详细讲解了)

                                         堆所处内存空间:物理上不连续,逻辑上连续即可,可以固定大小,可以扩展的(通过-Xmx和-Xms控制)

                                         异常:OutOfMemoryError异常(堆中没有完成实例分配,并且堆也无法在扩展时)

                       2.2.5        方法区

                                       内存类型:线程共享。

                                       存储数据:虚拟机加载的类信息,常量,静态变量,即时编译期变异后的代码数据。

                                       所属:堆逻辑上的一部分,也叫Non-Heap(就是为了和堆区分开,)

                                      内存空间:和堆一样不需要连续的内存存储空间,可以选择固定大小和可以扩展,还可以选择不实现垃圾收集。

                                       垃圾回收:常量池的回收和类型的卸载。

                                       异常:OutOfMemoryError异常

                         2.2.6      运行时常量池

                                        所属:方法区的一部分。

                                        存放数据:编译期生成的各种字面量和符号引用,这部分内容在类加载后进入方法区的运行时常量池中存放。

                                       特性:

                                         (1)java虚拟机对于class文件的每一部分的格式都有严格的规定,每一个字节的数据只有符合规范的要求才能被虚拟机认可,但是对于运行时常量池,java虚拟机没有做任何细节的要求,不同的厂商可以按照自己的需要来实现这个内存区域,处理保存在Class文件中的描述的符号引用外,还会把翻译出来的直接引用也存储到运行时常量池中,

                                         (2)动态性:java并不要求常量一定在编译期才能产生,运行期间也可以将新的常量放入池中,例如

String类中的intern()方法。

                                       异常: 当常量池无法在申请到内存时。

                                                 OutOfMemory异常

                      2.2.7    直接内存。

                                 直接内存(direct Memory)并不是虚拟机运行时候数据区的一部门,也并不是java虚拟机规范中定义的内存区域,但是这部分也被频繁的使用,也有可能导致OutofMemoryError异常。

                               在JDK1.4中新加入的NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使Native函数库直接分配堆外内存,然后通过一个存储在java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,这样能够在一些场景中提高性能,因为避免了java堆和Native堆中来回复制数据。

                                显然,本机直接内存的分配不会受到java堆大小的限制,但是,既然是内存,肯定会受到本机内存(包括RAM以及SWAP区或是分页文件)大小,以及处理区寻址空间的限制,服务器管理员在配置虚拟机参数的时候,会根据实际内存设置-Xmx等参数的信息,但经常忽略直接内存,使得各个内存区域总和大于物理内存的限制,从而导致动态扩展时出现OutOfMemoryErrir异常。

                      今天就学习到这里,明天添加java虚拟机对创建的????????????????????

猜你喜欢

转载自blog.csdn.net/qq_36262421/article/details/81606476