前一段时间总结了spring和springmvc相关的知识,面试中常问到的除了这些基本的框架之外,还有底层的基础知识,比如与java虚拟机相关的知识点,这一部分也是面试中经常问到的,在面试中高级java工程师的时候,这一部分是很重要的一个点,倘若一个程序员在这一块没有了解或者看过学习过相关的知识,那么他的基础就是相对薄弱的,面试成功的可能性也会降低很多.
这篇文章会把java的整体运行结构和jvm的关系做个梳理,但是不再用大篇幅的文字叙述的内容,这样不容易记忆,而且容易产生厌看的情绪.所以我决定使用采用绘图+少部分文字描述为主.

一、弄明白java的整体运行结构与jvm的关系

1. jvm是什么?

Java虚拟机(英语:Java Virtual Machine,缩写为JVM),一种能够运行Java bytecode的虚拟机,以堆栈结构机器来进行实做。最早由太阳微系统所研发并实现第一个实现版本,是Java平台的一部分,能够运行以Java语言写作的软件程序Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码-字节码,就可以在多种平台上不加修改地运行。通过对中央处理器CPU所执行的软件实现,实现能执行编译过的Java程序码与应用程序)。
作为一种编程语言的虚拟机,实际上不只是专用于Java语言,只要生成的编译文件匹配JVM对加载编译文件格式要求,任何语言都可以由JVM编译运行。此外,除了甲骨文,也有其他开源或闭源的实现。--摘自维基百科

2.java运行过程与jvm关系

上图能够清晰的展示我们从新编译一个java类到jvm中执行的全部流程,对堆栈等地方的功能做一个解释:

  • 堆:java的引用传递实现,依靠的就是堆内存,同一块堆内存可以被不同的栈内存所指向;
  • 栈:程序运行的单位,里面存储的信息都与当前的线程有关系,包括局部变量,程序的运行状态,方法返回值等;
  • 方法区:在进行递归调用时,所保存的堆栈内容,它由局部变量表,操作数栈,当前方法所属的类的运行时常量的引用,返回地址等;
  • 程序计数器:一块非常小的内存空间,主要用来做一个计数操作,对象的晋升问题(关系到垃圾回收(GC)).

二、堆内存组织结构以及与内存有关的参数设置(优化)

在整个jvm运行时数据区,要对jvm进行优化,那么堆内存是重点优化对象.原因是栈本身所占的内存比率很小,而java中所有new对象全部放在堆内存区域.那么对这些对象的回收控制策略就非常重要.

1.堆内存的内部结构


上图展示了堆内存的内部结构,值得注意的是,在1.8之前和之后,java的永久代被取消,被元空间所代替(元空间就是电脑本省的物理内存),下面对各个区的作用做简单的解释:
年轻代:

  • Eden区:新生的小对象,每当使用关键字new的时候,默认都会在此空间进行对象创建,如果创建的对象过多,那么最终的的结果就是Eden区的空间爆满,此时会发生晋级操作(在经历若干次minorGC后还保留的对象,晋升到存活区)
  • 存活区:minorGC存活的对象保存的区域,存活区有两块空间S0和S1,有一块始终为空,该区域保存对象向老年代晋升(停止-复制算法);
    老年代:经历了数次GC之后还保留的对象,这些对象经历了多次GC仍然存活,但是也有可能在接下来的某一次被清除掉,同时要注意,假如是new一个很大的对象,那么是直接保存到老年代来,如果老年代空间不够了,会出现MajorGC(FullGC)进行老年代的清理,非常耗费性能(不建议使用system.gc()的原因);
    在发生MajorGC的时候,jvm会检查每次晋升入老年代的对象的大小是否大于老年代剩余空间的大小,若大于,直接触发一次FullGC,否则可以自定义是否允许担保失败(关键字设置:XX:+HandlePromotionFailure)(标记-清理算法);
    元空间(永久代):jdk1.8之后,取消了永久代,变成了元空间,不再在堆内存里面保存类,字符串常量等,采用了元空间之后,不会再出现堆溢出的异常.

    2. 重要参数

    通过调整jvm的相关参数,可以优化堆内存,提高jvm的运行效率,下面对几个重要参数做一下总结:

  • -Xms:设置初始化的内存分配大小,,默认采用的大小为物理大小的1/64;
  • -Xmx:设置最大的内存可用空间,,默认采用的大小为物理大小的1/4;
  • -Xmn:设置年轻代大小,默认采用的大小为物理大小的1/64;
  • -Xss:设置每一个线程所占用的栈的大小

三、GC算法

在jdk1.7之后,正式发布了G1回收算法;
在此之前,GC算法的发展进程如下:

  1. Serial(串行)收集器
    在jdk1.3.1之前,java虚拟机仅仅能使用Serial收集器。 Serial收集器是一个单线程的收集器,但它的“单线程”的意义并不仅仅是说明它只会使用一个CPU或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。
  2. Parallel(并行)收集器
    Parallel收集器也称吞吐量收集器,相比Serial收集器,Parallel最主要的优势在于使用多线程去完成垃圾清理工作,这样可以充分利用多核的特性,大幅降低gc时间。
  3. CMS(并发)收集器
    CMS收集器在Minor GC时会暂停所有的应用线程,并以多线程的方式进行垃圾回收。在Full GC时不再暂停应用线程,而是使用若干个后台线程定期的对老年代空间进行扫描,及时回收其中不再使用的对象。
  4. G1(并发)收集器
    G1收集器(或者垃圾优先收集器)的设计初衷是为了尽量缩短处理超大堆(大于4GB)时产生的停顿。相对于CMS的优势而言是内存碎片的产生率大大降低。
    以上就是GC算法发展史,具体的各个算法有什么不同,暂时还没有特别深入的研究和比较,后续会再开一篇补上.

    总结

    这篇文章对java运行的流程和jvm的关系,以及jvm的内部结构,和jvm的堆内存优化,做了一个总结,但是GC算法是一个大头,一篇文章的篇幅实在是无法详述,后续再接再厉,争取把这一快吃透.

java虚拟机和内存优化总结的更多相关文章

  1. Java虚拟机之内存区域

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

  2. 如何写出让java虚拟机发生内存溢出异常OutOfMemoryError的代码

    程序小白在写代码的过程中,经常会不经意间写出发生内存溢出异常的代码.很多时候这类异常如何产生的都傻傻弄不清楚,如果能故意写出让jvm发生内存溢出的代码,有时候看来也并非一件容易的事.最近通过学习< ...

  3. 深入理解java虚拟机【内存溢出实例】

    通过简单的小例子程序,演示java虚拟机各部分内存溢出情况: (1).java堆溢出: Java堆用于存储实例对象,只要不断创建对象,并且保证GC Roots到对象之间有引用的可达,避免垃圾收集器回收 ...

  4. 从Java虚拟机的内存区域、垃圾收集器及内存分配原则谈Java的内存回收机制

    一.引言: 在Java中我们只需要轻轻地new一下,就可以为实例化一个类,并分配对应的内存空间,而后似乎我们也可以不用去管它,Java自带垃圾回收器,到了对象死亡的时候垃圾回收器就会将死亡对象的内存回 ...

  5. Java虚拟机:内存模型详解

    版权声明:本文为博主原创文章,转载请注明出处,欢迎交流学习! 我们都知道,当虚拟机执行Java代码的时候,首先要把字节码文件加载到内存,那么这些类的信息都存放在内存中的哪个区域呢?当我们创建一个对象实 ...

  6. 初识:java虚拟机的内存划分

    什么是内存? 内存是计算机中的重要原件,临时存储区域,作用是运行程序.我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存.Java虚拟机要运行程序 ...

  7. java虚拟机的内存模型

    一.为什么要了解java虚拟机的内存模型 java虚拟机作为java代码运行的平台,是java技术的基石.了解java虚拟机的内存模型也就变得十分必要.它能帮助我们更好的了解java代码的运行机制,更 ...

  8. java虚拟机的内存机制

    我们都知道,java程序的跨平台性离不开java虚拟机,虚拟机隔绝了底层操作系统,使得java程序可以直接运行在虚拟机之上.所以,对java的学习,离不开对java虚拟机的学习与了解.下面简单整理下j ...

  9. Java虚拟机的内存管理

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

随机推荐

  1. Java 工程师成神之路 | 2019正式版

    本文为转载,原文见以下链接:https://mp.weixin.qq.com/s/4AMzq87V6eW3YPgE0mCdSw 1 基础篇 01 面向对象 → 什么是面向对象 面向对象.面向过程 面向 ...

  2. 三、CSS样式——字体

    概念: CSS字体属性定义文本的字体系列.大小.加粗.风格和变形. 属性 描述 font-family 设置字体系列 font-size 设置字体的大小 font-style 设置字体的风格 font ...

  3. 合并hive/hdfs小文件

    磁盘: heads/sectors/cylinders,分别就是磁头/扇区/柱面,每个扇区512byte(现在新的硬盘每个扇区有4K) 文件系统: 文件系统不是一个扇区一个扇区的来读数据,太慢了,所以 ...

  4. 小程序2-基本架构讲解(一)WXSS样式

    项目里边生成了不同类型的文件: .json 后缀的 JSON 配置文件 .wxml 后缀的 WXML 模板文件 .wxss 后缀的 WXSS 样式文件 .js 后缀的 JS 脚本逻辑文件 WXSS 样 ...

  5. 快速傅里叶变换(FFT)时间复杂度

    图:信号在时域上和频域上的直观表示 1. 计算一维离散傅里叶变换(DFT)公式如下: 其中,N表示数据长度.由上式可知,DFT的时间复杂度是O(N*N) 2. 一维FFT的时间复杂度为O(N*logN ...

  6. Android 开发 图片网络缓存加载框架Fresco

    简介 Fresco是一个在Android应用程序中显示图像的强大系统. Fresco负责图像的加载和显示.它将从网络.本地存储或本地资源加载图像,图像加载完成前会显示一个占位图片.它有两个级别的缓存: ...

  7. [持续交付实践] 研发协作平台:DevOps背景下的组织结构

    前言 今年以来做的事情越来越杂,负责的技术方向越来越广,精力越来越分散(创业公司的典型特点),编码的时间越来越少,有时候也会觉得很疲惫没办法专注一个事情. 除了技术方向上的实践,组织上如何组建一个最优 ...

  8. 爬虫基础——HTTP基本原理

    ## 学习爬虫务必从了解请求网页的工作流程和网页的组成原理开始,不然直接去学爬虫操作像是请求库等等,大概率会知其然而不知其所以然(个人体会) URL和HTTP简介 URL(Uniform Resour ...

  9. 如何解决iOS界面操作导致导致NSTimer暂停计时的问题?

    在NSTimer代码后面加上以下代码,这样滚动scroll的时候就不会暂停了.NSRunLoop *t = [NSRunLoop currentRunLoop];[t addTimer: timer  ...

  10. python:windows下python2.7安装mysql-python失败【转】

    转自:https://www.cnblogs.com/yujiebingqing/p/9633476.html 当我们尝试用: 1 pip install mysql-python #并不是MySQL ...