天天看点

震惊!JVM是这样工作的?学习JVM知识的必要性项目启动后,JVM是如何工作的JVM内存划分Java会造成内存泄漏吗?

学习JVM知识的必要性

Java语言针对内存实行的是自动管理机制,不需要程序员在代码里写释放内存,垃圾回收的代码,JVM帮助你实现了这些功能。Java虽然有垃圾回收机制,但是有些垃圾是回收不了的,还是会造成内存泄漏,内存溢出等错误,如果你对JVM内存模型及运行机制不了解的话,当项目出现问题时,会束手无措。

项目启动后,JVM是如何工作的

1、服务器启动时,源代码被Java编译器,编译为字节码文件(.class)。

2、JVM中的类加载器将所有的字节码文件加载进JVM空间。

3、JVM执行引擎执行这些字节码文件。

4、执行的过程中,产生了很多数据,这些数据固定的存在某块空间,这块空间就是我们经常提到的JVM内存。

JVM内存划分

JVM共分为五个部分,分别是栈、堆、方法区、程序计数器,本地方法栈。我们运行的每一个项目都是一个进程,一个进程包含多个线程。

线程私有。

栈解决程序的运行问题,即程序如何执行,或者说如何处理数据。

在虚拟机中跑的所有的线程,每一个线程,都有一个自己的线程栈,这个栈是私有的,别人不能访问你的东西,线程栈包括了这个线程现在执行的方法,以及这个节点的相关信息。

每个线程栈由一个个的栈帧组成,每个栈帧对应一个调用的方法。

简而言之,栈执行字节码文件中的java方法。

线程共享。

堆是内存最大的一块区域,解决的是数据存储的问题,存放对象的实例。

我们经常遇到的内存报错,基本上都是这里搞出来的。比如你创建的实例对象太多了,堆的空间塞满了。

堆内部分为两个空间,新生代,老年代。

新创建的对象都在新生代这一块,如果经过多次GC仍然活着,就会被转移到老年代。

简而言之,出了问题,基本上都是堆内存分配的锅。

方法区

方法区有三个名字,方法区,非堆,永久代。

它和堆有点相像,都是线程共享,但是它存储的东西不一样,而且GC一般也不会跑到这里来。主要存储类信息,常量,静态变量等数据。

简而言之,不用管方法区是啥。

程序计数器

线程私有,字节码行号指示器。程序计数器是JVM规范中唯一一个没有任何OutOfMemoryError情况的区域。

简而言之,这个东西,基本上,你不会跟它有打交道的时候。

本地方法栈

线程私有,存放字面量及符号引用,本地方法栈执行Native方法。Native方法是指在Java中调用其他编程语言的方法。

简而言之,如果你没有用别的编程语言,那这个东西基本与你无瓜。

总结

五个区域,只有堆和方法区是线程共享的,其他都是线程私有。

Java会造成内存泄漏吗?

从概念上讲,Java有垃圾回收机制不会存在内存泄漏问题。

从现实中看,每个小区都有保洁对垃圾桶进行清理,偶尔会有那么一两个忘记清理了。

即有GC归有GC,总是有些藏污纳垢的地方。

在实际开发中,存在一些没有什么用的对象,这些对象不被GC回收,因而会导致内存泄漏的发生。

举例:

Hibernate中一级缓存设置,其中的对象就是持久型的,垃圾回收机制不回收这些东西,但是这些对象一定是有用的吗?非也,肯定有没用的,还不能GC掉,就导致了内存泄漏。