大数据技术之_30_JVM学习_01_JVM 位置+JVM 体系结构概览+堆体系结构概述+堆参数调优入门+JVM 的配置和优化+Tomcat 的配置和优化

1、JVM 位置2、JVM 体系结构概览3、堆体系结构概述4、堆参数调优入门5、JVM 的配置和优化6、Tomcat 的配置和优化



熟悉 JVM 架构与 GC 垃圾回收机制以及相应的 JVM 调优,有过在 Linux 系统下的调优经验。

淘宝的周志明《深入理解 Java 虚拟机》中说 JVM 的优化,其中 99% 优化的是堆,1% 优化的是方法区。

内地女歌手照片--李嘉欣,贴在桌面上。

1、JVM 位置

JVM 是运行在操作系统之上的,它与硬件没有直接的交互

2、JVM 体系结构概览

详解如下:

类装载器 Class Loader
  负责加载 class 文件,class 文件在文件开头有特定的文件标示,并且 Class Loader 只负责 class 文件的加载,至于它是否可以运行,则由 Execution Engine 决定。

虚拟机自带的加载器
  启动类加载器(Bootstrap)C++
  扩展类加载器(Extension)Java
  应用程序类加载器(AppClassLoader)Java
  也叫系统类加载器,加载当前应用的 classpath 的所有类

用户自定义的加载器
  Java.lang.ClassLoader 的子类,用户可以定制类的加载方式。
  Code 案例
  sun.misc.Launcher 它是一个 java 虚拟机的入口应用。

Execution Engine 执行引擎
  执行引擎负责解释命令,提交操作系统执行。

Native Interface 本地接口
  本地接口的作用是融合不同的编程语言为 Java 所用,它的初衷是融合 C/C++ 程序,Java 诞生的时候是 C/C++ 横行的时候,要想立足,必须有调用 C/C++ 程序,于是就在内存中专门开辟了一块区域处理标记为 native 的代码,它的具体做法是 Native Method Stack 中登记 native 方法,在 Execution Engine 执行时加载 native libraies。

  目前该方法使用的越来越少了,除非是与硬件有关的应用,比如通过 Java 程序驱动打印机或者 Java 系统管理生产设备,在企业级应用中已经比较少见。

  因为现在的异构领域间的通信很发达,比如可以使用 Socket 通信,也可以使用 Web Service 等等,不多做介绍。

Native Method Stack 本地方法栈
  它的具体做法是 Native Method Stack 中登记 native 方法,在 Execution Engine 执行时加载本地方法库。

PC Register 程序寄存器
  每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。

  这块内存区域很小,它是当前线程所执行的字节码的行号指示器,字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令。

  如果执行的是一个 Native 方法,那这个计数器是空的。

Method Area 方法区
  方法区是被所有线程共享,所有字段和方法字节码,以及一些特殊方法如构造函数,接口代码也在此定义。简单说,所有定义的方法的信息都保存在该区域,此区属于共享区间

  静态变量 + 常量 + 类信息(构造方法/接口定义) + 运行时常量池 存在方法区中,但是实例变量存在堆内存中,和方法区无关

  方法区主要存放的是:构造方法 + 接口的代码

Stack 栈是什么
  栈也叫栈内存,主管 Java 程序的运行,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束该栈就 over,生命周期和线程一致,是线程私有的。8 种基本类型的变量 + 对象的引用变量 + 实例方法都是在函数的栈内存中分配。

栈存储什么?
栈帧中主要保存 3 类数据:
  本地变量(Local Variables):输入参数和输出参数以及方法内的变量。
  栈操作(Operand Stack):记录出栈、入栈的操作。
  栈帧数据(Frame Data):包括类文件、方法等等。

栈运行原理
  栈中的数据都是以栈帧(Stack Frame)的格式存在,栈帧是一个内存区块,是一个数据集,是一个有关方法(Method)和运行期数据的数据集,当一个方法 A 被调用时就产生了一个栈帧 F1,并被压入到栈中,A 方法又调用了 B 方法,于是产生栈帧 F2 也被压入栈,B 方法又调用了 C 方法,于是产生栈帧 F3 也被压入栈,…… 执行完毕后,先弹出 F3 栈帧,再弹出 F2 栈帧,再弹出 F1 栈帧,……

  遵循 “先进后出”/“后进先出” 原则。

  每个方法执行的同时都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每一个方法从调用直至执行完毕的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。栈的大小和具体 JVM 的实现有关,通常在 256K~756K 之间。

  栈内存溢出异常:Exception in thread "main" java.lang.StackOverflowError

  栈管运行,堆管存储。

三种 JVM
  1、Sun 公司的 HotSpot(Oracle 收购)
  2、BEA 公司的 JRockit(Oracle 收购)
  3、IBM 公司的 J9 VM

3、堆体系结构概述

JVM 优化的是哪里?

Heap 堆
  一个 JVM 实例只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行,堆内存分为三部分:

  • Young Generation Space 新生区 Young/New
  • Tenure generation space 养老区 Old/Tenure
  • Permanent Space 永久区 Perm

Heap 堆(Java7 之前)
  一个 JVM 实例只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行。
  堆内存逻辑上分为三部分:新生 + 养老 + 永久

新生区
  新生区是类的诞生、成长、消亡的区域,一个类在这里产生、应用、最后被垃圾回收器收集、结束生命。新生区又分为两部分:伊甸区(Eden space)和幸存者区(Survivor pace),所有的类都是在伊甸区被 new 出来的。幸存区有两个:0 区(Survivor 0 space)和 1 区(Survivor 1 space)。当伊甸园的空间用完时,程序又需要创建对象,JVM 的垃圾回收器将对伊甸园区进行垃圾回收
(Minor GC),将伊甸园区中的不再被其他对象所引用的对象进行销毁。然后将伊甸园中的剩余对象移动到幸存 0 区。若幸存 0 区也满了,再对该区进行垃圾回收,然后移动到 1 区。那如果
1 区也满了呢?再移动到养老区。若养老区也满了,那么这个时候将产生 Major GCFull GC),进行养老区的内存清理。若养老区执行了 Full GC 之后发现依然无法进行对象的保存,就会产生 OOM 异常 “OutOfMemoryError”。

  如果出现 java.lang.OutOfMemoryError: Java heap space 异常,说明 Java 虚拟机的堆内存不够。原因有二:
  (1)Java 虚拟机的堆内存设置不够,可以通过参数 -Xms、-Xmx 来调整
  (2)代码中创建了大量大对象,并且长时间不能被垃圾收集器收集(存在被引用)
  如何 new 一个大对象? 答:byte[] byteArray = new byte[1 * 1024 * 1024 * 7000];

养老区
  养老区用于保存从新生区筛选出来的 Java 对象,一般池对象都在这个区域活跃。

永久区
  永久存储区是一个常驻内存区域,用于存放 JDK 自身所携带的 Class、Interface 的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭 JVM 才会释放此区域所占用的内存。

  如果出现 java.lang.OutOfMemoryError: PermGen space,说明是 Java 虚拟机对永久代 Perm 内存设置不够。一般出现这种情况,都是程序启动需要加载大量的第三方 jar 包。例如:在一个 Tomcat 下部署了太多的应用。或者大量动态反射生成的类不断被加载,最终导致 Perm 区被占满。

  Java 7 叫永久代,Java 8 叫元空间。

  实际而言,方法区(Method Area)和堆一样,是各个线程共享的内存区域,它用于存储虚拟机加载的:类信息+普通常量+静态常量+编译器编译后的代码等等,虽然 JVM 规范将方法区描述为堆的一个逻辑部分,但它却还有一个别名叫做 Non-Heap(非堆),目的就是要和堆分开。

  对于 HotSpot 虚拟机,很多开发者习惯将方法区称之为“永久代(Parmanent Gen)”,但严格本质上说两者不同,或者说使用永久代来实现方法区而已,永久代是方法区(相当于是一个接口 interface)的一个实现jdk1.7 的版本中,已经将原本放在永久代的字符串常量池移走

jdk 1.6 方法区就是永久代。常量池在方法区中。
jdk 1.7 中 常量池放在了堆中。

RUNTIME CONSTANT POOL 运行时常量池
  常量池(Constant Pool)是方法区的一部分,Class 文件除了有类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池,常量池用于存放编译期间生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

熟悉三区结构后方可学习-JVM 垃圾收集

4、堆参数调优入门

JVM 垃圾收集(Java Garbage Collection)
以 JDK1.7 + HotSpot 为例

以 JDK1.8 + HotSpot 为例

堆内存调优简介 01

堆内存调优简介 02
发现默认的情况下分配的内存是总内存的“1 / 4”、而初始化的内存为“1 / 64”


调整 VM 参数并打印出来:-Xms1024m -Xmx1024m -XX:+PrintGCDetails

堆内存调优简介 03
java 7


java 8

堆内存调优简介 04
调整 VM 参数并打印出来:-Xms8m -Xmx8m -XX:+PrintGCDetails
java 7


java 8

MAT(Eclipse Memory Analyzer Tool)


官网访问地址:https://projects.eclipse.org/projects/tools.mat/downloads

安装方式1:离线 jar 包方式
1)Eclipse Memory Analyzer Windows 64 位下载地址:http://www.eclipse.org/downloads/download.php?file=/mat/1.8.1/rcp/MemoryAnalyzer-1.8.1.20180910-win32.win32.x86_64.zip
2)解压下载包:放到 eclipse 或 myeclipse 安装目录的 dropins 目录下。
3)启动 eclipse 或 myeclipse,打开 Window - > Perspective,看到 Memory Analyzer 证明安装成功。

安装方式2:联网插件安装方式
http://download.eclipse.org/mat/1.8.1/update-site/

使用 MAT 分析
  启动 eclipse 或 myeclipse,打开 File - > Open heap dump,在弹出的对话框选择生成的 dump文件,就可以看到 MAT 给出了overview page。

面试题

5、JVM 的配置和优化

JVM 复习

GC 是什么
  频繁收集 新生区,使用的算法是复制算法
  较少收集 老年区,使用的算法是
  基本不动 永久区 (jdk7)

GC 三大算法

GC 算法总体概述

复制算法:Minor GC(普通 GC)
新生代中使用的是 Minor GC(普通 GC),这种 GC 算法采用的是复制算法(Copying)
复制算法的原理如下图所示:

Minor GC(普通 GC)会把 Eden 中的所有活的对象都移到 Survivor 区域中,如果 Survivor 区域中放不下,那么剩下的活的对象就被移动到 Old Generation 中,也即一旦收集后,Eden 就变成空的了

复制算法的缺点:

标记清除算法/标记整理算法:Full GC 又叫 Major GC(全局 GC)
老年代一般是由标记清除或者是标记清除与标记整理的混合实现。

标记清除:Mark-Sweep
标记清除原理

标记清除算法的缺点:

标记整理:Mark-Compact
标记整理算法原理

标记整理算法的缺点:

小总结

面试题

6、Tomcat 的配置和优化


(1)点击【参数配置】选项,Eclipse 中的 Tomcat 一般在默认情况下内存偏小,运行一会儿就会抛出内存溢出错误,需要在 Tomcat 的 VM arguments 中添加如下参数:-Xms128M -Xmx512M -XX:PermSize=512m -XX:MaxPermSize=1024m,具体大小根据自己的电脑硬件。最后点击下面的 "OK" 按钮保存配置。

(2)45秒和15秒分别是tomcat启动和停止的超时时间,该长一些,防止工程较大启动慢造成工程启动不了。

(3)Eclipse默认将工程部署至eclipse的目录中,目录层次较深不易操作,这里改到tomcat自己的部署目录中。
注意:如果eclipse的tomcat已添加工程需要在eclipse中将tomcat下的工程全部移除后方可设置该项。

配置完成后,要点击【保存】按钮。

原文地址:https://www.cnblogs.com/chenmingjun/p/11029371.html

时间: 2024-10-12 22:36:35

大数据技术之_30_JVM学习_01_JVM 位置+JVM 体系结构概览+堆体系结构概述+堆参数调优入门+JVM 的配置和优化+Tomcat 的配置和优化的相关文章

大数据技术之_16_Scala学习_11_客户信息管理系统+并发编程模型 Akka+Akka 网络编程-小黄鸡客服案例+Akka 网络编程-Spark Master Worker 进程通讯项目

第十五章 客户信息管理系统15.1 项目的开发流程15.2 项目的需求分析15.3 项目的界面15.4 项目的设计-程序框架图15.5 项目的功能实现15.5.1 完成 Customer 类15.5.2 完成显示主菜单和退出软件功能15.5.3 完成显示客户列表的功能15.5.4 完成添加客户的功能15.5.5 完成删除客户的功能15.5.6 完善退出确认功能15.5.7 完善删除确认功能15.5.8 完成修改客户的功能第十六章 并发编程模型 Akka16.1 Akka 的介绍16.2 Acto

大数据技术之_20_Elasticsearch学习_01_概述 + 快速入门 + Java API 操作 + 创建、删除索引 + 新建、搜索、更新删除文档 + 条件查询 + 映射操作

一 概述1.1 什么是搜索?1.2 如果用数据库做搜索会怎么样?1.3 什么是全文检索和 Lucene?1.4 什么是 Elasticsearch?1.5 Elasticsearch 的适用场景1.6 Elasticsearch 的特点1.7 Elasticsearch 的核心概念1.7.1 近实时1.7.2 Cluster(集群)1.7.3 Node(节点)1.7.4 Index(索引 --> 数据库)1.7.5 Type(类型 --> 表)1.7.6 Document(文档 -->

大数据技术之_03_Hadoop学习_02_入门_Hadoop运行模式+【本地运行模式+伪分布式运行模式+完全分布式运行模式(开发重点)】+Hadoop编译源码(面试重点)+常见错误及解决方案

第4章 Hadoop运行模式4.1 本地运行模式4.1.1 官方Grep案例4.1.2 官方WordCount案例4.2 伪分布式运行模式4.2.1 启动HDFS并运行MapReduce程序4.2.2 启动YARN并运行MapReduce程序4.2.3 配置历史服务器4.2.4 配置日志的聚集4.2.5 配置文件说明4.3 完全分布式运行模式(开发重点)4.3.1 虚拟机准备4.3.2 编写集群分发脚本xsync4.3.3 集群配置4.3.4 集群单点启动4.3.5 SSH无密登录配置4.3.6

大数据技术之_08_Hive学习_01_Hive入门+Hive安装、配置和使用+Hive数据类型

第1章 Hive入门1.1 什么是Hive1.2 Hive的优缺点1.2.1 优点1.2.2 缺点1.3 Hive架构原理1.4 Hive和数据库比较1.4.1 查询语言1.4.2 数据存储位置1.4.3 数据更新1.4.4 索引1.4.5 执行1.4.6 执行延迟1.4.7 可扩展性1.4.8 数据规模第2章 Hive安装.配置和使用2.1 Hive安装地址2.2 Hive安装部署2.3 将本地文件导入Hive案例2.4 MySql安装2.4.1 安装包准备2.4.2 安装MySql服务器2.

大数据技术之_05_Hadoop学习_04_MapReduce_Hadoop企业优化(重中之重)+HDFS小文件优化方法+MapReduce扩展案例+倒排索引案例(多job串联)+TopN案例+找博客共同粉丝案例+常见错误及解决方案

第6章 Hadoop企业优化(重中之重)6.1 MapReduce 跑的慢的原因6.2 MapReduce优化方法6.2.1 数据输入6.2.2 Map阶段6.2.3 Reduce阶段6.2.4 I/O传输6.2.5 数据倾斜问题6.2.6 常用的调优参数6.3 HDFS小文件优化方法6.3.1 HDFS小文件弊端6.3.2 HDFS小文件解决方案第7章 MapReduce扩展案例7.1 倒排索引案例(多job串联)7.2 TopN案例7.3 找博客共同粉丝案例第8章 常见错误及解决方案 第6章

大数据技术之_10_Kafka学习_Kafka概述+Kafka集群部署+Kafka工作流程分析+Kafka API实战+Kafka Producer拦截器+Kafka Streams

第1章 Kafka概述1.1 消息队列1.2 为什么需要消息队列1.3 什么是Kafka1.4 Kafka架构第2章 Kafka集群部署2.1 环境准备2.1.1 集群规划2.1.2 jar包下载2.2 Kafka集群部署2.3 Kafka命令行操作第3章 Kafka工作流程分析3.1 Kafka 生产过程分析3.1.1 写入方式3.1.2 分区(Partition)3.1.3 副本(Replication)3.1.4 写入流程3.2 Broker 保存消息3.2.1 存储方式3.2.2 存储策

大数据技术之_16_Scala学习_08_数据结构(下)-集合操作+模式匹配

第十一章 数据结构(下)-集合操作11.1 集合元素的映射-map11.1.1 map 映射函数的操作11.1.2 高阶函数基本使用案例1+案例211.1.3 使用 map 映射函数来解决11.1.4 模拟实现 map 映射函数的机制11.1.5 课堂练习11.2 集合元素的扁平-flatMap11.3 集合元素的过滤-filter11.4 集合元素的化简-reduce11.5 集合元素的折叠-fold11.6 集合元素的扫描-scan11.7 集合的综合应用案例11.8 集合的合并-zip11

大数据技术之_19_Spark学习_02_Spark Core 应用解析小结

1.RDD 全称 弹性分布式数据集 Resilient Distributed Dataset它就是一个 class. abstract class RDD[T: ClassTag](    @transient private var _sc: SparkContext,    @transient private var deps: Seq[Dependency[_]]  ) extends Serializable with Logging { 继承了 Serializable 和具有 L

大数据技术之_19_Spark学习_02_Spark Core 应用解析+ RDD 概念 + RDD 编程 + 键值对 RDD + 数据读取与保存主要方式 + RDD 编程进阶 + Spark Core 实例练习

第1章 RDD 概念1.1 RDD 为什么会产生1.2 RDD 概述1.2.1 什么是 RDD1.2.2 RDD 的属性1.3 RDD 弹性1.4 RDD 特点1.4.1 分区1.4.2 只读1.4.3 依赖1.4.4 缓存1.4.5 CheckPoint第2章 RDD 编程2.1 RDD 编程模型2.2 RDD 创建2.2.1 由一个已经存在的 Scala 集合创建,即集合并行化(测试用)2.2.2 由外部存储系统的数据集创建(开发用)2.3 RDD 编程2.3.1 Transformatio