热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

JVM《基础篇》

我们学的是oracle的jvm学习路线:程序计数器:定义:ProgramcounterRegister程序计数器(寄存器)作用,是记住下一条jabm指令得执行地址特点是线程私有得,

我们学的是oracle的jvm

学习路线:


程序计数器:


定义:

Program counter Register 程序计数器(寄存器)

作用,是记住下一条jabm指令得执行地址

特点

是线程私有得,每一个线程都有自己得程序计数器(主要用于记住,当前执行到线程代码得地址)

不会存在内存溢出


回顾数据结构栈:

先进后出,后进先出的原则,

参考递归

栈-线程运行需要的内存空间,

一个栈有多个栈帧组成

栈帧对应一次方法的调用,所以,在线程运行的时候每个方法需要的内存我们称为栈帧。

栈帧:每个方法运行时需要的内存;

这里回顾一下方法调用的操作:main 调用方法a ,a方法内部调用的b,这个时候按照栈的加载进入程序,最后释放的是main方法;


Java Virtual Machine Stacks(java虚拟机栈)

*)每个线程运行时需要的内存,称为虚拟机栈

*)每个栈帧由多个(Rrame重新载入帧)组成,对应着每次方法调用时所占用的内存

*)每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法 (栈顶部栈帧称为活动栈帧)

问题::

1.垃圾回收是否涉及我们的栈内存?

不需要,栈内存是栈帧的一次次调用,栈帧内存在每一次结束调用后,都会被弹出栈,会被自动回收掉,不需要垃圾回收,垃圾回收回收的是堆内存中的无用对象,栈内存不需要。不会也不需要

2.栈内存分配越大越好么?

内存越大,线程数越小,(物理内存是固定的,),假设:一个线程使用的栈内存使用的1兆的内存,我物理内存是500,理论上可以运行五百个线程;

如果我给每个给每个栈内存设置了2兆的内存,理论上就变成只能运行250个线程。

建议使用系统默认内存

错,栈内存过大,相应就是代码增多,提高了解耦难度,冗余度也随之提高

这里可以指定栈内存的大小(-Xss),不指认大小,会跟根据操作系统默认大小

Windows,会根据自身的虚拟内存来影响每个栈的大小


3.方法内部的局部变量是否线程安全?

1.分析这个变量是否私有还是线程共有:是否static修饰

线程不共用一个变量的时候:

局部变量,对应一个栈帧,线程内每次调用一个方法都会产生一个栈帧,

也就是说不同线程拿到的成员变量都是自己私有的一个变量。他们各自++互不干扰;

我们通过案来理解

这个栈帧是安全的,栈帧加载后创建出的局部变量,其他线程是访问不到的

这个局部变量是不安全的,它以形参方式传递进来,有可能会被其他线程访问并且修改掉数据(形参共享)

局部变量本身是安全的,但是被当成返回结果返回了,这就有可能被其他线程拿到这个结果来引用,并且并发的去修改它,这个时候就不再是安全的了。



栈内存溢出:

学习什么情况下导致 内存溢出


1.栈帧过多,栈内存是固定的

导致溢出

递归调用如果没有设置一个正确的计数条件,就会导致不停的产生栈帧。(在不明却递归条件的值是否安全是,避免使用递归)


2.栈帧过大!

基本不会出现这种情况,基本不存在,栈帧过大出现溢出,都是栈帧过多。

设置栈内存的大小:

1

2


3:日常开发中,第三方库也会导致 stackOverflowError

转json用OjectMapper的时候,部门包含员工,员工包含部门,形成一个递归映射的关系,导致现栈内存溢出。 (两个类之间的循环引用关系导致递归死循环)

解决方式:

在转json转的过程中打断这种关系,比如:

我转换员工的时候,遇到这个部门转换,我们就不转了;(把双向关系,打破转变成单项关系)


线程运行诊断:


案例1:cpu占用过多:!!!

定位线程(Linux)

一定要避开这个问题!!


案例2:程序运行很长时间没有结果:


Native Mthod Stacks (本地方法栈)

就是一些java基本构成的一些方法,他们没有具体返回值,native的方法声明,它的方法实现都是通过c来实现的, 我们的java代码通过这个native间接的去调用本地方法接口去调用c或从c++的实现,Object里面的方法基本都是。


Heap(堆)

通过new关键字,创建对象都会使用堆内存

特点:

*)它是线程共享的,堆中对象都要考虑线程安全的问题;

*)有垃圾回收机制


outOfMemoryError错误经典案例:

4G运行了26次空间不够


-Xmx8m堆内存空间设置(8m)

17次空间不够


堆内存诊断(Heap stacks)


jps工具:

查看当前系统中有那些Java进程

命令jps查看进程id


jmap工具:

查看堆内存占用清空(工具使用代码:jmap -heap)


jconsole工具

图形界面的,多功能监测工具,可以连续检测

(命令就是jconsole)


最好用的工具jvistualvm:


案例:垃圾回收后,内存占用仍然很高

堆赚储


Method Area(方法区):

CGlib动态代理的实现Spring,mybatis,ClassWriter。他们底层都实现了一个叫ClassVisitor的字节码接口。用于实现动态代理,

CGlib也有ClassWriter,他们都出自一个类,都是在运行期间动态生成类字节码。代理技术里面广泛引用到这个技术。

堆中方法区,定义永久代

元空间(现在使用操作操作 系统的分配)

1.6的时候存储在永久代,但是1.8之后永久代这个实现被废弃了,

但是方法区还是概念上的东西;

它的实现,变成了method space(元空间),不过它已经不占用堆内存了。

已经不是由jvm在管理,移存到本地内存去了(heap堆中);


线程共享区域,存储了一些类结构的信息;


field 成员变量;


method data 方法数据;


code for methods and consrructors

就是我们的成员方法以及构造器方法他们的代码 包括一些special method特殊方法;


还有运行时常量池:run-time-constant-pool(单独说)


方法区内存溢出:


1.8以前会导致永久代内存溢出

-XX:MaxMetaspaceSize=8m

永久代会被GC管理

这里主要演示的是元空间的内存溢出,元空间中是基于系统内存来分配的,跟物理运行内存有关;

public class PermGenOverflowTest extends ClassLoader{
@Test
public void permGenOverflow(){
int j=0;
try{
PermGenOverflowTest test = new PermGenOverflowTest();
for (int i = 0; i <10000; i++,j++) {
//ClassWriter 生成二进制字节码
ClassWriter writer = new ClassWriter(0);
//版本号 权限修饰符 类名 父类 接口
writer.visit(Opcodes.V1_8,Opcodes.ACC_PUBLIC,"Class"+i,null,"java/lang/Object",null);
byte [] code = writer.toByteArray();
test.defineClass("Class"+i,code,0, code.length);//只执行了类的加载
}
}finally {
System.out.println(j);
}
}
}

Metaspace空间导致的内存溢出


1.8之后会导致元空间内存溢出

这里介绍一个类:Clasloader类//用来加载类的二进制字节码

ClassWtier作用时生成类的二进制字节码

添加参数给元内存空间指定大小

动态生成场景


运行时常量池:

常量池中进行的赋值操作,程序计数器也是在这里

javap -c 类名.class


常量池与串池的关系:

常量池中的信息,都会被加载到运行时常量池中;这时都是常量池中的符号,还没

有变为java中的字符串对象;


类的组成

反编译一个类查看

javap -v App.class//反编译一个类,查看这个类信息

这个是时候,串池是这样的StringTable[]


串池:

是一个hashtable的结构,不能扩容

1.如果字符a在串池中没有,StringTable[“a”]中添加a,都是串池先找一圈;

2.懒惰的模式;执行到,用到它的时候才会去创建或查找它;

在串池中,相同数据(地址)只会存储一次

位置不一样new的在堆里面

所以这里是新存储了两条地址,里面有new操作

hash链表特性:相同值,相同地址认定为同一个数据,相同数据会


讲解:

这里说一下,intern操作是把当前对象(数据)放入串池(结果是true)

String a = new String("b")+new String("a");
String b= a.intern();
System.out.println(a==b);

这里讲解一下如果intern放入串池的内容存在不会再放入,返回原值

所以这里a是false b是true

String c = "ba";
String a = new String("b")+new String("a");
String b= a.intern();
System.out.println(a==c);
System.out.println(b==c);

1.8是直接将对象放入串池

主要是看水先入池
String a = new String("b")+new String("a");
a.intern();
String c = "ba";
System.out.println(a==c);

1.6是复制一份放入串池

这里是1.6测试:


String Tabele位置

确认位置通过报错这里先看1.6:

1.8的

关掉垃圾回收机制后得出报错是heap溢出


String Table 调优:

添加的垃圾回收的信息:会打印内存占用,如果有垃圾会收会打印GC

这里是一些类名啊,变量名啊,他们也是以字符串存储的;也属于常量池;SymbolTable

String Table 底层类似于hashtable的实现;是数组加链表的结构,数组的个数称为桶

默认桶个数60013(红黑树结构 )

这里没有引发垃圾回收机制因为100次还不足以引发但是可以看到串池的增长是一个百个

这里存一万个,发现只存了7000多

这里打印了一条由于内存空间分配失败触发了垃圾回收


GC垃圾回收的规则

就是我用了98%的经历来回收垃圾,但是只起到2%的作用,我就开始抛出异常不在处理

StringTable也是回受到垃圾回收机制的管理的, 当内存空间不足时,string table 那些 没有被引用的字符串常量,也会被回收;


演示StringTable的垃圾回收机制:

 



推荐阅读
  • JVM参数设置与命令行工具详解
    JVM参数配置与命令行工具的深入解析旨在优化系统性能,通过合理设置JVM参数,确保在高吞吐量的前提下,有效减少垃圾回收(GC)的频率,进而降低系统停顿时间,提升服务的稳定性和响应速度。此外,本文还将详细介绍常用的JVM命令行工具,帮助开发者更好地监控和调优JVM运行状态。 ... [详细]
  • Python与R语言在功能和应用场景上各有优势。尽管R语言在统计分析和数据可视化方面具有更强的专业性,但Python作为一种通用编程语言,适用于更广泛的领域,包括Web开发、自动化脚本和机器学习等。对于初学者而言,Python的学习曲线更为平缓,上手更加容易。此外,Python拥有庞大的社区支持和丰富的第三方库,使其在实际应用中更具灵活性和扩展性。 ... [详细]
  • Java中高级工程师面试必备:JVM核心知识点全面解析
    对于软件开发人员而言,随着技术框架的不断演进和成熟,许多高级功能已经被高度封装,使得初级开发者只需掌握基本用法即可迅速完成项目。然而,对于中高级工程师而言,深入了解Java虚拟机(JVM)的核心知识点是必不可少的。这不仅有助于优化性能和解决复杂问题,还能在面试中脱颖而出。本文将全面解析JVM的关键概念和技术细节,帮助读者全面提升技术水平。 ... [详细]
  • 深入解析零拷贝技术(Zerocopy)及其应用优势
    零拷贝技术(Zero-copy)是Netty框架中的一个关键特性,其核心在于减少数据在操作系统内核与用户空间之间的传输次数。通过避免不必要的内存复制操作,零拷贝显著提高了数据传输的效率和性能。本文将深入探讨零拷贝的工作原理及其在实际应用中的优势,包括降低CPU负载、减少内存带宽消耗以及提高系统吞吐量等方面。 ... [详细]
  • java堆的内存规整_java内存分配与溢出
    Java程序而言,Java虚拟机有自动内存管理机制,不需要开发人员去手动释放内空间,也不容易出现内存泄漏和溢出的问题,一切看 ... [详细]
  • 基于Node.js的高性能实时消息推送系统通过集成Socket.IO和Express框架,实现了高效的高并发消息转发功能。该系统能够支持大量用户同时在线,并确保消息的实时性和可靠性,适用于需要即时通信的应用场景。 ... [详细]
  • 本文深入探讨了JVM的核心机制,重点解析了堆内存与栈内存的功能与特性。JVM栈主要负责程序的执行流程,包括方法调用和数据处理;而JVM堆则专注于数据的存储管理,主要用于存放对象实例。栈内存中存储的是基本数据类型以及堆中对象的引用,确保了程序在运行时能够高效地访问和操作数据。 ... [详细]
  • 本课程详细解析了Spring AOP的核心概念及其增强机制,涵盖前置增强、后置增强和环绕增强等类型。通过具体示例,深入探讨了如何在实际开发中有效运用这些增强技术,以提升代码的模块化和可维护性。此外,还介绍了Spring AOP在异常处理和性能监控等场景中的应用,帮助开发者更好地理解和掌握这一强大工具。 ... [详细]
  • 本文探讨了Python 3.6中引入的`secrets`模块,该模块专为生成高质量的加密随机数而设计,旨在提升应用程序中的机密管理和安全性。通过使用`secrets`模块,开发者可以有效防止常见的安全漏洞,确保敏感数据的保护。 ... [详细]
  • 寻找数组 O(n) 中两数组合的最小和值 ... [详细]
  • 在Java NIO中,`ByteBuffer` 的内存分配方式分为 `allocate` 和 `allocateDirect`。前者在JVM堆内存中分配空间,返回 `HeapByteBuffer` 实例,初始位置为0,容量和限制由参数指定。而 `allocateDirect` 则在操作系统本地内存中分配,返回 `DirectByteBuffer`,适用于需要频繁与I/O操作交互的场景,性能更高但管理成本较大。两者在内存管理和性能上各有优劣,选择时需根据具体应用场景权衡。 ... [详细]
  • 深入解析JDK中的四种随机数生成器
    我们从jdk8说起。主要是四个随机数生成器。神马?有四个? 接下来我们简单说下这几个类的使用场景,来了解其中的细微差别,和a ... [详细]
  • Joomla!软件介绍【Joomla!概括介绍】国外相当知名的内容管理系统。【Joomla!基本介绍】Joomla!是一套在国外相当知名的内容管理系统(ContentManagem ... [详细]
  • Javajpa调用存储过程,抛出异常如下:javax.persistence.PersistenceException:org.hibernate.exception.Generi ... [详细]
  • java的jvm原理_Java面试之JVM原理总结
    1、什么是JVM?答:JVM是JavaVirualMachine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,他 ... [详细]
author-avatar
kaining_huang_750
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有