JVM学习笔记——内存结构篇( 八 )

StringTable垃圾回收问题StringTable会自动进行垃圾回收 , 这也是我们在JDK运行中选择StringTable的原因之一
我们通过一个简单的案例进行解释:
package cn.itcast.jvm.t1.stringtable;import java.util.ArrayList;import java.util.List;/** * 演示 StringTable 垃圾回收 * -Xmx10m -XX:+PrintStringTableStatistics(打印StringTable内容) -XX:+PrintGCDetails -verbose:gc(打印垃圾回收) */public class Demo1_7 {public static void main(String[] args) throws InterruptedException {int i = 0;try {for (int j = 0; j < 100000; j++) { // 设置1w个数// 这里如果不采用.intern()// 我们会发现1w个数全部存入内存中String.valueOf(j);i++;}} catch (Throwable e) {e.printStackTrace();} finally {System.out.println(i);}}}/** * 演示 StringTable 垃圾回收 * -Xmx10m -XX:+PrintStringTableStatistics(打印StringTable内容) -XX:+PrintGCDetails -verbose:gc(打印垃圾回收) */public class Demo1_7 {public static void main(String[] args) throws InterruptedException {int i = 0;try {for (int j = 0; j < 100000; j++) { // 设置1w个数// 这里如果采用.intern()// 我们会发现StringTable里面的值会少于1w , 这是因为发生了垃圾回收 , 回收掉不使用的信息String.valueOf(j).intern();i++;}} catch (Throwable e) {e.printStackTrace();} finally {System.out.println(i);}}}StringTable调优最后我们介绍StringTable的调优方法:

  1. 设置桶的个数
// 我们直到StringTable是一个哈希表,哈希表里面桶的个数会影响其效率// 如果桶过少,每个桶存储信息过多导致查找缓慢;如果桶过多,导致信息分布较为疏散导致查找缓慢// 我们提供一个配置来改变桶的个数:-XX:StringTableSize=10000(需要设计恰到好处的桶个数)package cn.itcast.jvm.t1.stringtable;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;/** * 演示串池大小对性能的影响 * -Xms500m -Xmx500m -XX:+PrintStringTableStatistics -XX:StringTableSize=1009 */public class Demo1_24 {public static void main(String[] args) throws IOException {try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("linux.words"), "utf-8"))) {String line = null;long start = System.nanoTime();while (true) {line = reader.readLine();if (line == null) {break;}line.intern();}System.out.println("cost:" + (System.nanoTime() - start) / 1000000);}}}
  1. 考虑字符串对象是否入池
// 我们同样可以采用intern来判断该字符串是否应该入池// 我们排除掉相同的字符串自然可以节省空间~package cn.itcast.jvm.t1.stringtable;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.List;/** * 演示 intern 减少内存占用 * -XX:StringTableSize=200000 -XX:+PrintStringTableStatistics * -Xsx500m -Xmx500m -XX:+PrintStringTableStatistics -XX:StringTableSize=200000 */public class Demo1_25 {public static void main(String[] args) throws IOException {List<String> address = new ArrayList<>();System.in.read();for (int i = 0; i < 10; i++) {try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("linux.words"), "utf-8"))) {String line = null;long start = System.nanoTime();while (true) {line = reader.readLine();if(line == null) {break;}// 如果这里不采用.tern会导致全部字符串进入,导致储存较多address.add(line);}System.out.println("cost:" +(System.nanoTime()-start)/1000000);}}System.in.read();}}/** * 演示 intern 减少内存占用 * -XX:StringTableSize=200000 -XX:+PrintStringTableStatistics * -Xsx500m -Xmx500m -XX:+PrintStringTableStatistics -XX:StringTableSize=200000 */public class Demo1_25 {public static void main(String[] args) throws IOException {List<String> address = new ArrayList<>();System.in.read();for (int i = 0; i < 10; i++) {try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("linux.words"), "utf-8"))) {String line = null;long start = System.nanoTime();while (true) {line = reader.readLine();if(line == null) {break;}// 如果这里采用.tern就会筛选字符串,来进行调优~address.add(line.tern());}System.out.println("cost:" +(System.nanoTime()-start)/1000000);}}System.in.read();}}直接内存这小节我们来介绍系统中常用的直接内存
直接内存简介我们先来介绍一下直接内存的定义:
  • 直接内存不受JVM内存回收管理
  • 直接内存是直接受管于系统的内存,不能被JVM所调配
  • 直接内存通常用于NIO操作 , 用于数据缓冲区,其分配成本较高,但读写性能较高
直接内存详细介绍我们通过一段代码来展示直接内存的速度:
package cn.itcast.jvm.t1.direct;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;/** * 演示 ByteBuffer 作用 */public class Demo1_9 {static final String FROM = "E:\\编程资料\\第三方教学视频\\youtube\\Getting Started with Spring Boot-sbPSjI4tt10.mp4";static final String TO = "E:\\a.mp4";static final int _1Mb = 1024 * 1024;public static void main(String[] args) {io(); // io 用时:1535.586957 1766.963399 1359.240226directBuffer(); // directBuffer 用时:479.295165 702.291454 562.56592}// directBuffer(直接内存读取数据)private static void directBuffer() {long start = System.nanoTime();try (FileChannel from = new FileInputStream(FROM).getChannel();FileChannel to = new FileOutputStream(TO).getChannel();) {ByteBuffer bb = ByteBuffer.allocateDirect(_1Mb);while (true) {int len = from.read(bb);if (len == -1) {break;}bb.flip();to.write(bb);bb.clear();}} catch (IOException e) {e.printStackTrace();}long end = System.nanoTime();System.out.println("directBuffer 用时:" + (end - start) / 1000_000.0);}// io(jvm正常读取数据)private static void io() {long start = System.nanoTime();try (FileInputStream from = new FileInputStream(FROM);FileOutputStream to = new FileOutputStream(TO);) {byte[] buf = new byte[_1Mb];while (true) {int len = from.read(buf);if (len == -1) {break;}to.write(buf, 0, len);}} catch (IOException e) {e.printStackTrace();}long end = System.nanoTime();System.out.println("io 用时:" + (end - start) / 1000_000.0);}}

推荐阅读