Java学习之二(线程(了解) JVM GC 垃圾回收)

线程与进程(了解)→JVM→字节码→GC

一、程序 = 算法 + 数据结构(大佬)

二、程序 = 框架 + 业务逻辑(现实)

1.线程与进程、同步与异步

  1.1进程是什么?

  进程就是操作系统控制的基本运行单元,说白了就是Java运行程序。

  1.2什么是线程?

  进程中独立运行的子任务就是一个线程

  1.3什么是多线程(异步)?

  多线程是多个子任务进行交替执行。例如:有A、B两个任务,A先执行,再执行B,如果是单线程执行,则需要等A先执行完之后才能够执行B;而多线程的话是A与B来回交换执行。这样可以让系统的运行效率大大的提高。

  多线程是异步的。

  1.4同步与异步

  同步:有两个程序:程序A与程序B,程序A调用程序B时,A等待B执行完成之后再执行。

  异步:有两个程序:程序A与程序B,程序A调用程序B时,A不会等待B的执行,而是会自动的执行下去。

  1.5线程共享与独享

  线程共享:可优化,可回收

  线程独享:不可优化,不可回收

2.JVM及内存调优

  2.1JVM

  JVM是Java Virtual Machine,是java虚拟机的缩写。JVM的本质上就是一段程序;JVM有5大模块:类装载子系统、运行时数据区、执行引擎、本地方法接口、垃圾回收机制。JVM实现了一次编译多次运行的特点,关键原因在于在编译成java字节码后,不管在什么平台上只要存在JVM虚拟机,就能够执行这个字节码,不用多次编译,这也是java跨平台的原因。

  先来一张大致图:

  2.2字节码

  java字节码(.class),它是由java源文件(.java)通过java编译器编译而来的二进制流文件。是一种8位字节的文件。

  2.3JVM的生命周期

  在执行Java程序时,有几个程序执行就会有几个JVM(以下成为Java虚拟机)。Java虚拟机的只要还有程序执行就会一直存在,它的执行只能从main方法为起点进行执行,main方法称为初始线程。

  Java中的线程分为两种:一、守护线程(一般是Java虚拟机自己使用的线程,当然也可以自己定义守护线程)     二、普通线程

  在Java虚拟机中如果还存在普通线程,则Java虚拟机会一直执行。

  2.4Java内存管理(参考上面的图)

  类装载器(ClassLoader):负责加载.class文件。

  虚拟机中有四种加载器,

  JVM自带加载器:1.启动类加载器(bootstrap)(在jvm启动的时候就加载,使用的new就是在启动的时候自动加载);2.扩展类加载器(Extension);3.应用程序类加载器(AppClassLoader);

  用户自己定义的加载器:1.继承java.lang.ClassLoader;

  通过代码来进行查看,JVM自带的类加载器

public class demo01 {
    public static void main(String[] args) {
        demo01 demo01 = new demo01();
        //通过反射获取类加载器的父类的父类
        System.out.println(demo01.getClass().getClassLoader().getParent().getParent());
        //通过反射获取类加载器的父类
        System.out.println(demo01.getClass().getClassLoader().getParent());
        //通过反射获取类加载器
        System.out.println(demo01.getClass().getClassLoader());
    }
}

  运行结果为:

  程序可得在进行类加载的时候,执行了应用程序类加载器、扩展程序类加载器,而启动加载器并未使用;这时候我们看jdk自带的Object类又是怎样的:

 1 public class demo01 {
 2     public static void main(String[] args) {
 3         Object obj = new Object();
 4         demo01 demo01 = new demo01();
 5         System.out.println(obj.getClass().getClassLoader());
 6         //通过反射获取类加载器的父类的父类
 7         System.out.println(demo01.getClass().getClassLoader().getParent().getParent());
 8         //通过反射获取类加载器的父类
 9         System.out.println(demo01.getClass().getClassLoader().getParent());
10         //通过反射获取类加载器
11         System.out.println(demo01.getClass().getClassLoader());
12     }
13 }

运行结果

出现这种情况的原因,个人认为这是在JVM启动的时候就自动的执行了启动类加载器,并且加载了JDK中定义的类;

  本地方法区与本地方法接口

  native:调用底层第三方函数库(说明白一点就是调用C语言或者操作系统的函数库)

    带有native关键字的方法全部进入本地方法栈,而不带native关键字的方法进入java栈;

  程序计数器

    每一个线程都有一个程序计数器,程序计数器记录了执行顺序。占用空间十分小,几乎可以忽略不计。

  方法区/永久带(线程共享)

    所有方法定义的信息都保存在方法区中,有:静态变量 + 常量 + 类信息(构造方法/接口信息) + 常量池

    类的元数据(元数据并不是类的Class对象!Class对象是加载的最终产品,类的方法代码,变量名,方法名,访问权限,返回值等等都是在方法区的)

  

    栈与队列

    栈:后进先出,所以也装入方法,其中main方法一定实在栈底;

    队列:先进先出

  栈中存放数据:本地变量/局部变量(输入参数、输出参数、方法变量)、对象引用(使用指针进行对象的访问)

  

  逻辑上:在JDK1.7之前,分为 新生区 -- 养老区 --  永久区;在JDK1.8及以后,永久区被去除

  一般来说,大多对象都是在新生区被回收;有部分对象在新生区中未被回收(轻回收,发生在伊甸园),则进入养老区(例如数据库连接池,重GC回收机制);如果养老区执行回收机制还是腾不出空间,则会出现OOM错误异常(俗称堆溢出)。

  物理上:   新生区   ---   养老区

  永久区(一般存放jar包)

  jDK 1.6 有永久带,常量池在方法区

  JDK 1.7有永久带,永久代存在于虚拟机中,常量池在堆

  JDK 1.8 无永久带,常量池在元空间,元空间并不在虚拟机中,而是存在于本地内存;

  堆调优

  通过代码,查看虚拟机内存相关情况

  

 1 public class Demo01 {
 2     public static void main(String[] args) {
 3         //虚拟机试图使用的最大内存
 4         long max01 = Runtime.getRuntime().maxMemory();
 5         //虚拟机内存的总量
 6         long max02 = Runtime.getRuntime().totalMemory();
 7         System.out.println("" + max01/1024/1024 + "M");
 8         System.out.println("" + max02/1024/1024 + "M");
 9     }
10 }

  运行结果如下

1801M
123M

Process finished with exit code 0

简单介绍

  -Xms 设置初始分配大小,默认为物理内存的  1/64;

  -Xmx 设置最大分配内存,默认为物理内存的  1/4;

  -XX:+PrintGCDetails   打印GC回收信息

  上面的我物理内存大小为 8G,计算结果也大致相似。

JVM参数调优设置(IDEA):

  

我这里将最大内存与初始内存设置为100M

运行结果为:

96M
96M
Heap
 PSYoungGen      total 29696K, used 2584K [0x00000000fdf00000, 0x0000000100000000, 0x0000000100000000)
  eden space 25600K, 10% used [0x00000000fdf00000,0x00000000fe1861c0,0x00000000ff800000)
  from space 4096K, 0% used [0x00000000ffc00000,0x00000000ffc00000,0x0000000100000000)
  to   space 4096K, 0% used [0x00000000ff800000,0x00000000ff800000,0x00000000ffc00000)
 ParOldGen       total 68608K, used 0K [0x00000000f9c00000, 0x00000000fdf00000, 0x00000000fdf00000)
  object space 68608K, 0% used [0x00000000f9c00000,0x00000000f9c00000,0x00000000fdf00000)
 Metaspace       used 3144K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 343K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0

设置成功!

  测试堆溢出

  这里我将大小设置为1M,代码如下

  

 1 public class Demo02 {
 2     public static void main(String[] args) {
 3         //虚拟机试图使用的最大内存
 4         long max01 = Runtime.getRuntime().maxMemory();
 5         //虚拟机内存的总量
 6         long max02 = Runtime.getRuntime().totalMemory();
 7         System.out.println("" + max01/1024/1024 + "M");
 8         System.out.println("" + max02/1024/1024 + "M");
 9         String a = "abc";
10         while (true){
11             a = a + new Random().nextInt(123456);
12         }
13     }
14 }

  成功堆溢出,出现OOM错误

[Full GC (Ergonomics) [PSYoungGen: 512K->477K(1024K)] [ParOldGen: 511K->477K(512K)] 1023K->955K(1536K), [Metaspace: 3738K->3738K(1056768K)], 0.0141204 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOfRange(Arrays.java:3664)
    at java.lang.String.<init>(String.java:207)
    at java.lang.StringBuilder.toString(StringBuilder.java:407)
    at org.study.heapstudy.Demo02.main(Demo02.java:15)

  关于内存调优尚有不懂,以后补充。这里先留一个,内存分析工具:JProFiler

3.Java垃圾回收简单概述

  1.1为什么会存在垃圾回收机制?

  如果不进行垃圾回收,则会造成资源的占用,持续下去内存的话,内存迟早要被消耗一空;所以引入垃圾回收机制,在恰当的时机进行垃圾的回收,释放掉一些内存。相对与C来说,Java的垃圾回收机制是自动的,并不需要手动的去回收垃圾。

  1.2如何理解垃圾回收机制?

  前面说到堆有几个时期,   新生区 --- 养老区   --- 永久区(理论存在,物理上并不在JVM中,而是元空间中也就是物理内存中)。当养老区满了却又无法释放的时候,则会造成堆溢出。同理新生区如果没有垃圾回收的话,也会造成堆溢出;

  1.3 哪些对象不会被回收?

  栈、本地方法栈、方法区。

  1.4 GC清除算法?

   1.4.1  标记清理算法   缺点:会产生内存碎片

   1.4.2  标记整理算法   优点:减少内存碎片       缺点:对象迁移,代价大

   1.4.3  复制算法          缺点:需要两倍的内存

   新生代(伊甸园(存活的进入一区,没用的就直接被回收)、一区、二区)  养老带(存放年龄 >= 6,或者存放大对象);注意一区、二区交替工作  比例为 1:1:8

原文地址:https://www.cnblogs.com/yyuanyu/p/11823372.html

时间: 2024-10-13 14:47:50

Java学习之二(线程(了解) JVM GC 垃圾回收)的相关文章

【转载】JAVA学习路线二

JAVA学习路线二------------高阶面试 作者:Java高级进阶链接:https://zhuanlan.zhihu.com/p/35301291来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 1.hashcode相等两个类一定相等吗?equals呢?相反呢? 2.介绍一下集合框架? 3.hashmap hastable 底层实现什么区别?hashtable和concurrenthashtable呢? 4.hashmap和treemap什么区别?低层数据结

Java学习笔记二:初始化(一)

1.对象初始化 在使用 new 初始化对象时,系统通常使用默认的构造函数,这个构造函数没有返回值,格式为: public class InitializeTest { private int a; // 默认构造函数 public InitializeTest() { } // 自定义构造函数 public InitializeTest(int a) { this.a = a; } } 虽然在使用 new 创建实例时,返回了这个对象的引用,但是这个与没有返回值的void方法不同 //void方法

Java学习笔记二:数据类型

Java学习笔记二:数据类型 1. 整型:没有小数部分,允许为负数,Java整型分4种:int short long byte 1.1 Int最为常用,一个Int类型变量在内存中占用4个字节,取值范围从-2 147 483 6至2 147 483 647 超过20亿,如果用来存储大于20亿的值,最好使用long型. 1.2  int 与Integer: Java中的数据类型分为基本数据类型和复杂数据类型.Int为前者,integer为后者. Integer是int的封装类,提供了很多转换方法,当

面试官,不要再问我“Java GC垃圾回收机制”了

Java GC垃圾回收几乎是面试必问的JVM问题之一,本篇文章带领大家了解Java GC的底层原理,图文并茂,突破学习及面试瓶颈. 楔子-JVM内存结构补充 在上篇<JVM之内存结构详解>中有些内容我们没有讲,本篇结合垃圾回收机制来一起学习.还记得JVM中堆的结构图吗? 图中展示了堆中三个区域:Eden.From Survivor.To Survivor.从图中可以也可以看到它们的大小比例,准确来说是:8:1:1.为什么要这样设计呢,本篇文章后续会给出解答,还是根据垃圾回收的具体情况来设计的.

JVM优化 垃圾回收 算法 垃圾收集器 GC日志可视化查看

今日内容了解什么是垃圾回收掌握垃圾会回收的常见算法学习串行.并行.并发.G1垃圾收集器学习GC日志的可视化查看 1.什么是垃圾回收?程序的运行必然需要申请内存资源,无效的对象资源如果不及时处理就会一直占有内存 资源,最终将导致内存溢出,所以对内存资源的管理是非常重要了. 1.1.C/C++语言的垃圾回收在C/C++语言中,没有自动垃圾回收机制,是通过new关键字申请内存资源,通过delete 关键字释放内存资源.如果,程序员在某些位置没有写delete进行释放,那么申请的对象将一直占用内存资源,

【JAVA进阶架构师指南】之四:垃圾回收GC

前言 ??在[JAVA进阶架构师指南]系列二和三中,我们了解了JVM的内存模型以及类加载机制,其中在内存模型中,我们说到,从线程角度来说,JVM分为线程私有的区域(虚拟机栈/本地方法栈/程序计数器)和线程公有区域(方法区和java堆),其中线程私有区域内存随着线程的结束而跟着被回收,GC主要关注的是堆和方法区这部分的内存. GC回收算法 ??GC如何确定哪些对象需要回收呢?一般而言,有两种算法:引用计数算法和可达性分析算法. 引用计数算法 ??为每个对象都持有一个引用计数器,初试状态为0,该对象

JVM虚拟机垃圾回收(GC)算法及优缺点

一.什么是GC GC是jvm的垃圾回收,垃圾回收的规律和原则为: 次数上频繁收集新生区(Young) 次数上较少收集养老区(Old) 基本上不动永久区(Perm) 二.GC算法(分代收集算法) GC总共有四大算法,分别是: ①引用计数法 ②复制算法(Copying) ③标记清除(Mark-Sweep) ④标记压缩(Mark-Compact) ⑤标记清除压缩(Mark-Sweep-Compact) 1.1 引用计数法 1.2 复制算法(Copying) 复制算法主要用在新生代中. 1.2.1 复制

JVM的垃圾回收机制(GC)

1.什么是垃圾回收                程序运行会产生各种各种的数据,那么这些数据存在于内存当中,这些数据不可能是永久存在的,无效的资源对象需要进行垃圾回收,释放内存            2.不同的编程语言都有GC垃圾回收                java语言自带GC垃圾回收器,并且有JVM自动进行垃圾回收,程序员主要关注代码实现,不关注垃圾回收 System.gc();                C/C++语言当中,程序员new一个对象,相当于申请了一块内存,如果需要释放

03 JVM的垃圾回收机制

1.前言 理解JVM的垃圾回收机制(简称GC)有什么好处呢?作为一名软件开发者,满足自己的好奇心将是一个很好的理由,不过更重要的是,理解GC工作机制可以帮助你写出更好的Java程序. 在学习GC前,你应该知道一个技术名词:"stop-the-world" ,无论你选择哪种GC算法,"stop-the-world"都会发生."stop-the-world"意味着JVM停止应用程序,而去进行垃圾回收.当"stop-the-world&quo