新生代收集器 Parallel Scavenge
新生代,多线程,使用复制算法,是多线程的并行的收集器。目标:达到一个可控的**吞吐量(Throughput)**。吞吐量:CPU用于运行代码时间 与 CPU总消耗时间的 比公式: 吞吐量 = 运行代码时间 / ( 运行代码时间 + GC时间)虚拟机运行 100 分钟,GC用掉1分钟,则吞吐量为99%。 100 /(100 + 1) = 0.99
停顿时间越短越好-XX:MaxGCPauseMillis: 最大GC停顿时间,最小可为0-XX:GCTimeRatio: 吞吐量大小,1-100
停顿时间与空间成反比停顿时间越短,则新生代的空间就越小。通过减小新生代的空间,让里面的垃圾变少,从而加快了集速度。原来:500MB 垃圾,10秒收集一次,每次停顿100毫秒为了缩短时间,修改** -XX:MaxGCPauseMillis** 参数,使新生代空间变小,产生的垃圾就少了,停顿时间短了:现在:300MB 垃圾,5秒收集一次, 每次停顿70毫秒。
那时问题来了,停顿时间下降了,但是频率高了,则吞吐量也跟着降下来了。
GC 时间占总时间的比例GCTimeRatio 进行这个设置1-100 ...
java 解决JDK内置工具不能使用问题
问题在服务器上准备排查服务进程问题,想使用jstat和jcmd这些工具,然后发现给我报了个错:
bash: jstat: command not found
这是什么鬼,程序正常跑着,难道JDK还有阉割版?看看版本,这个很正常。
123java version "1.8.0_291"Java(TM) SE Runtime Environment (build 1.8.0_291-b10)Java HotSpot(TM) 64-Bit Server VM (build 25.291-b10, mixed mode)
那去看看bin下面是不是把这些工具全删了:
1echo $JAVA_HOME
结果没有 JAVA_HOME 路径,这难道又是从/usr/bin指过去的,怎么总是喜欢这么玩。
1which java
结果,还真的是
/bin/java
那再看看这个java是指向哪里的:执行命令
1ll /bin/java
显示路径是:
/bin/java -> /etc/alternatives/java
那么也就是指向了 /etc/alterna ...
java exception和error异常和错误
体系我们在使用java的时,经常面对和处理的是异常(Exception)很少处理错误。因为如果是错误级别的往往都是比较底层的非代码层面的问题。但是这两个的区别,有必搞清楚。这两个是一对难兄难弟,有问题的时候都会出现这两兄弟。
通过图片可以直观的看出它们的体系,这图点开看比较清楚:
异常 Exception这个是最常遇见的问题,主要是由于编码原因异常的问题。我们开发过程中常见的是运行时异常,就是字面意思,运行时才知道的异常,运行时,才会有可能抛出来的异常。那相对的,就有非运行时的异常,就是不需要运行,也能知道是异常。
而异常当中,又有几个概念,这些概念性的东西,只是帮助分类和理解,使用场景可以说是经常遇见,分别是:
两种异常:
运行时异常 RuntimeException
异常 Exception
运行时异常 RuntimeException只有运行时才会知道是否有异常,比如下面这段代码会不会抛常异?
123456public class Test { public void test(int a, int b) { int c = a / b; ...
多线程 如何停止一个线程
前言这看似一个完全没有意义的问题,但是如果你是从搜索引擎过来的话,那么说明你碰到过这个问题。线程执行完不就退出了,说停止有什么意义?当然有意义,意义在于,一般创建线程后,如果是一次性的线程,执行结束就可以了,不用管它。如果是一个一直需要保持运行,而需要在某一时刻才需要停止的线程,就需要关注线程是如何退出的。
退出方式
退出标志: 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
interrupt: 使用interrupt方法中断线程。
可以但不推荐: 不推荐使用 stop、suspend及resume 方法。stop 相当于电脑断电关机一样,是不安全的方法。
退出标志方式:使用一个标志不控制线程是否需要继续执行。常驻的业务线程当中一般都会写循环,如果不写循环,一句话能搞定的事或者需要调用才执行的事,就没必要再开线程来处理。stop方法已经过时,不推荐使用。
开启多线程时,运行代码通常是循环结构,只要控制住循环,就可以让run方法结束,也就是线程结束。原理:只要循环终止了,线程也就终止了。
1234567891011121314151617public class S ...
对象的创建
这里指普通 Java 对象,而非数组 和 Class对象等。
1.创建对象的过程new ---> 到常量池中检查是否存在一个类的符号引用 ---> 如果有,检查这个符号引用代表的类是否已被加载、解析、初始化 ---> 没有,则执行类加载过程。
2.分配对象类加载完毕后,为新生对象分配内存。对象所需内存大小在类加载完成后便完全确定。分配空间。即,从JVM堆中划出一块确定大小的内存空间。
3.分配方法有两种分配方法:
指针碰撞:使用这种方式的前提是,内存是规整的。左边是空闲的空间,右边是已使用的内存空间,用一块,就往左边移一块,就像秤砣在称中间移动一样。
空闲列表内存不规整,此时不能使用指针碰撞。JVM 就需要维护一个列表,记录哪些空间可用并给对象。
堆内存是否规整决定了使用哪种分配方法。而堆是否会规整则由GC是否带有压缩整理功能决定。
4.避免并发操作同一片内存的问题并发时,A线程 拿着指针在为对象分配 0x111111 这片空间,分配动作执行到一半,B线程 也进来了拿着同一个指针在同一个地址上分配空间。这就出现了问题。
解决方案
CAS 配置失败重试的方式保证更 ...
引用级别
引用级别意义:用来标记对角是否可以被回收级别:强 > 软 > 弱 > 虚
1.强引用即一般普通的引用。如果一个对象是强引用,绝对不会被回收,即使内存空间不足也不会被回收,而是抛 OutOfMemoryError 异常使程序终止。
123String str = "abc";List<String> list = new Arraylist<String>();list.add(str);
在list集合里的数据不会释放,即使内存不足也不会
1Object obj = new Object();
//可直接通过obj取得对应的对象 如obj.equels(new Object());而这样 obj对象对后面new Object的一个强引用,只有当obj这个引用被释放之后,对象才会被释放掉,这是经常用到的编码形式。
2.软引用非必须引用,如果空间不足就会被GC回收。换句话说,在内存溢出之前进行回收。只要没有被回收,该对象就可能被程序使用。软引用可用来实现内存敏感的高速缓存。软引用可以和一个引用队列(ReferenceQu ...
Java 堆内存简介
Java 堆 是虚拟机管理的最大的一块内存。是被所有线程所共享的一块内存区域,在虚拟机启动时创建。
分配内存方式所有的实例和数组都在要堆上分配,但是随着JIT编译器的发展与逃逸分析技术的逐渐成熟,栈上分配、标量替换优化技术将会导至一些变化,所有的对象都分配在堆上也变得不那么绝对。
Java 堆是垃圾收集器管理的主要区域,也叫CG堆。由于现在收集器基本都爱用分代收集算法,所以Java堆中还可以细分为:新生代 和 老年代。再细致一点的有: Eden 空间、From Survivor 空间、To Survivor 空间等。从内存分配的角度来看,线程共享的Java堆中可能划多个线程私有的分配缓存区。
如何划分与存放内容无关,无论哪个区域,存储的都仍然是对象实例。进一步划分的目的是为了更好的回收内存、或都更快的分配内存。
存放特点Java 堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像磁盘空间。堆的实现,即可固定大小,也可以扩展,通过 -Xms 和 -Xmx 控制。如果堆中没有内存实例分配,并助理堆无法再扩展时,抛出 OutOfMemoryError
Java 虚拟机简单理解
与PC寄存器一样,Java虚拟机栈也是线程私有的。每一个JVM线程都有自己的java虚拟机栈,这个栈与线程同时创建,它的生命周期与线程相同。
1.虚拟机栈的特点“虚拟机栈”描述的是Java方法执行的内存模型:
每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储:局部变量表、操作数栈、动态链接、方法出口等信息。(栈帧我的理解就是一个对象,用来存储信息用)
每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
局部变量表
存放了8种基本数据 类型
对象引用 类型
returnAddress 类型
除64位 long 和 duble 占2个局部空间外,其余的数据类型只占1个。注意,局部变量表所需的内存空间在编译期间完成分配,所以进入某个方法时,这个方法需要在栈桢中分配多大的空间完全是确定的,在方法运行时是不会改变局部变量表的大小的。
3.虚拟机栈出现异常两种情况
如果线程请求的深度大于虚拟机所允许的深度,将抛出 StackOverflowError 异常;
如果虚拟机进行动态扩展,而扩展时无法申请到足够的内存,则抛出 Out ...
循环引用是否会被回收
前言见过一个问题说,如果java里的对象出现了循环引用,对象会不会被回收。结论是:会。因为 java 的对象存活算法,使用的是可达性分析算法,而不是引用计算法,java中任何一款GC都没有使用过引用计算法。
示例:
1234567891011public static void main(String[] args) throws IOException { A a = new A(); B b = new B(); a.bb = b; b.aa = a; //a = null; //b = null; System.in.read();}
多线程 生产者消费者模式
多生产消费者模式真正的开发环境下,不可能只有两条线程在跑,但是也有特殊情况,就是只需要两条线程来处理。比如一个线程生产,一个线程消费。这是一种线程协作,这种情场景下,生产者 和 消费者会操作同一个共享变量。看到这里的小伙伴应该是对线程的基本用法有一定了解,这里就直接开始明确几个概念
生产者
生产数据的线程,比如产生订单
消费者
处理生产者产生的订单
实际环境中,生产数据的速度要大于消费的速度,这个现象在很多场景中都存在。
共享变量
会被多个线程共同访问的变量
生产者、消费者模式本质是,通过严格控制两个线程的交替执行,来实现一个生产、一个消费的模式,数据存储在共享变量中。
可以再扩展一下,比如常用的MQ,也是一种生产者消费者模式,Producer 生产消费,Consumer消费消息。
主要资源12345678910111213141516171819202122232425262728293031323334/** * @author liukai * @since 2017/2/18. */public class Resource { private bool ...