当前位置: 首页 > wzjs >正文

互联网公司简介在线排名优化

互联网公司简介,在线排名优化,网页开发多少钱,做网站虚拟主机多少钱文章目录 定义字符串常量池的位置JDK 1.7 为什么要将字符串常量池移动到堆中? StringTable案例1案例2案例3案例4案例5案例6总结 StringTable 垃圾回收案例1.创建100个字符串(不会触发垃圾回收)2.创建10000个字符串(触发垃圾回收) StringTable 性能调优1.调整StringT…

文章目录

  • 定义
    • 字符串常量池的位置
    • JDK 1.7 为什么要将字符串常量池移动到堆中?
  • StringTable
    • 案例1
    • 案例2
    • 案例3
    • 案例4
    • 案例5
    • 案例6
    • 总结
  • StringTable 垃圾回收案例
    • 1.创建100个字符串(不会触发垃圾回收)
    • 2.创建10000个字符串(触发垃圾回收)
  • StringTable 性能调优
    • 1.调整StringTable哈希桶个数参数:调整 -XX:StringTableSize=桶个数
    • 2.考虑将字符串对象是否入池


在这里插入图片描述

定义

字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。

// 在字符串常量池中创建字符串对象 ”ab“
// 将字符串对象 ”ab“ 的引用赋值给给 aa
String aa = "ab";
// 直接返回字符串常量池中字符串对象 ”ab“,赋值给引用 bb
String bb = "ab";
System.out.println(aa==bb); // true
  • HotSpot 虚拟机中字符串常量池的实现是 src/hotspot/share/classfile/stringTable.cpp
  • StringTable 可以简单理解为一个固定大小的HashTable ,容量为 StringTableSize(可以通过 -XX:StringTableSize 参数来设置)。
  • 保存的是字符串(key)和 字符串对象的引用(value)的映射关系,字符串对象的引用指向堆中的字符串对象。

字符串常量池的位置

JDK1.7 之前,方法区的具体实现是永久代(Permanent Generation),字符串常量池存放在方法区(永久代)。
在这里插入图片描述
JDK 7 开始,字符串常量池和静态变量从永久代中移动到了 Java 堆中,但方法区仍然由永久代实现。这一改变主要是为了避免永久代的内存溢出问题,因为永久代的空间相对较小,且难以进行调优,而堆的管理相对更加灵活。
在这里插入图片描述
JDK 8 及以后的版本中,永久代被元空间(Metaspace)所取代,但字符串常量池仍然在堆中。元空间使用的是本地内存,不再受 JVM 堆内存的限制。方法区由元空间实现,它主要存储类的元数据信息,而字符串常量池独立于元空间,在堆中进行管理。

JDK 1.7 为什么要将字符串常量池移动到堆中?

主要是因为永久代(方法区实现)的 GC 回收效率太低,只有在整堆收集 (Full GC)的时候才会被执行 GC。Java 程序中通常会有大量的被创建的字符串等待回收,将字符串常量池放到堆中,能够更高效及时地回收字符串内存。

注意:运行时常量池、方法区、字符串常量池这些都是不随虚拟机实现而改变的逻辑概念,是公共且抽象的,Metaspace、Heap 是与具体某种虚拟机实现相关的物理概念,是私有且具体的。

StringTable

String Table 是JVM内部用于管理字符串常量池的数据结构。它是实现字符串常量池的具体形式,通常实现为一个哈希表,用于存储字符串对象的引用。通过String.intern()方法可以手动将字符串添加到String Table中,从而使得这些字符串能够在整个JVM范围内共享。

案例1

public static void main(String[] args) {String s1 = "a";String s2 = "b";String s3 = "ab";
}

执行javap -v Demo.class
在这里插入图片描述
观察
在这里插入图片描述
常量池中的信息,都会被加载到运行时常量池中, 这时 a、b、ab 都是常量池中的符号,还没有变为java 字符串对象。
当具体执行到指定的代码行时,才会变成java字符串对象(懒加载)。如执行:
在这里插入图片描述
ldc #2 会把 a 符号变为 “a” 字符串对象
ldc #3 会把 b 符号变为 “b” 字符串对象
ldc #4 会把 ab 符号变为 “ab” 字符串对象
当变为字符串对象后,会将如a为key,放入StringTable中(如果没有该key则放入)
StringTable ( “a”, “b” ,“ab” ) 是 hashTable 结构,不能扩容。

案例2

    public static void main(String[] args) {String s1 = "a";String s2 = "b";String s3 = "ab";String s4 = s1 + s2; // new StringBuilder().append("a").append("b").toString()  new String("ab")}

执行javap -v Demo.class

  public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=5, args_size=10: ldc           #2                  // String a2: astore_13: ldc           #3                  // String b5: astore_26: ldc           #4                  // String ab8: astore_39: new           #5                  // class java/lang/StringBuilder 创建StringBuilder对象//new StringBuilder12: dup13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V 调用无参构造方法//new StringBuilder()16: aload_1 //加载s1        17: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;//new StringBuilder().append("a")20: aload_221: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;//new StringBuilder().append("a").append("b")24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;//new StringBuilder().append("a").append("b").toString()27: astore        4 //s4字符串存入LocalVariableTable中的4号位置29: return

StringBuilder中的toString方法重新创建了一个新的String字符串

public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence
{@Overridepublic String toString() {// Create a copy, don't share the arrayreturn new String(value, 0, count);}
}

所以s3不等于s4

public static void main(String[] args) {String s1 = "a"; // 懒惰的String s2 = "b";String s3 = "ab";String s4 = s1 + s2; // new StringBuilder().append("a").append("b").toString()System.out.println(s3 == s4);//false
}

案例3

    public static void main(String[] args) {String s1 = "a"; // 懒惰的String s2 = "b";String s3 = "ab";String s4 = s1 + s2; // new StringBuilder().append("a").append("b").toString()  new String("ab")String s5 = "a" + "b";  // javac 在编译期间会进行优化//因为是两个字符串拼接而不是变量,所以结果已经在编译期确定为abSystem.out.println(s3 == s5);//true}

执行javap -v Demo.class

  public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=3, locals=6, args_size=10: ldc           #2                  // String a2: astore_13: ldc           #3                  // String b5: astore_26: ldc           #4                  // String ab8: astore_39: new           #5                  // class java/lang/StringBuilder12: dup13: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V16: aload_117: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;20: aload_221: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;24: invokevirtual #8                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;27: astore        429: ldc           #4                  // String ab31: astore        5

在这里插入图片描述

案例4

使用intern()将字符串对象尝试放入串池

public static void main(String[] args) {String s = new String("a") + new String("b");//注意:// "a"和"b"是常量,所以会放在串池中// new String("a")和new String("b")会放在堆内存中,// s也一样,因为是两个String对象使用了StringBuilder拼接,所以生成一个新的对象new String("ab")String s2 = s.intern();//将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池,会把串池中的对象返回System.out.println(s == "ab");//trueSystem.out.println(s2 == "ab");//true
}

案例5

//先将ab放入串池
String x = "ab";
String s = new String("a") + new String("b");
String s2 = s.intern();//因为ab已经在串池中,所以没有放入,直接返回的是串池中的对象
System.out.println(s == x);//false
System.out.println(s2 == x);//true

先调用intern()

String s = new String("a") + new String("b");
String s2 = s.intern();//因为ab已经在串池中,所以没有放入,直接返回的是串池中的对象
String x = "ab";
System.out.println(s == x);//true
System.out.println(s2 == x);//true

案例6

public static void main(String[] args) {String s1 = "a";String s2 = "b";String s3 = "a" + "b";  //因为是字符串拼接,所以直接变为 "ab"String s4 = s1 + s2;    //因为是两个变量拼接,所以会在运行期间通过StringBuild做字符串拼接,在堆中创建新的对象String s5 = "ab";       //因为常量池中已经有"ab",所以直接引用常量池中的对象String s6 = s4.intern();//因为"ab"已经放入串池,所以s4没有放入串池,而是直接引用常量池中的对象//s3在常量池中,s4在堆中System.out.println(s3 == s4);//falseSystem.out.println(s3 == s5);//trueSystem.out.println(s3 == s6);//trueSystem.out.println("======================");String x2 = new String("c") + new String("d");String x1 = "cd";x2.intern();System.out.println(x1 == x2);//falseSystem.out.println("======================");String y2 = new String("x") + new String("y");y2.intern();String y1 = "xy";System.out.println(y1 == y2);//true
}

总结

  • 常量池中的字符串仅是符号,第一次用到时才变为对象
  • 利用串池的机制,来避免重复创建字符串对象
  • 字符串变量拼接的原理是 StringBuilder (1.8)
  • 字符串常量拼接的原理是编译期优化
  • 可以使用 intern 方法,主动将串池中还没有的字符串对象放入串池
    注意:
    • 1.8 将这个字符串对象尝试放入字符串常量池,如果有则并不会放入,如果没有则把此对象放入串池, 会把串池中的对象返回
    • 1.6 将这个字符串对象尝试放入字符串常量池,如果有则并不会放入,如果没有会把此对象复制一份,放入串池, 会把串池中的对象返回(只会将对象副本放入串池)

StringTable 垃圾回收案例

设置参数
-Xmx10m -XX:+PrintStringTableStatistics -XX:+PrintGCDetails -verbose:gc

/*** 演示 StringTable 垃圾回收* -Xmx10m -XX:+PrintStringTableStatistics -XX:+PrintGCDetails -verbose:gc*/
public class Demo {public static void main(String[] args) throws InterruptedException {int i = 0;try {} catch (Throwable e) {e.printStackTrace();} finally {System.out.println(i);}}
}

打印

0
HeapPSYoungGen      total 2560K, used 1955K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)eden space 2048K, 95% used [0x00000000ffd00000,0x00000000ffee8c18,0x00000000fff00000)from space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)to   space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)ParOldGen       total 7168K, used 0K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)object space 7168K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffd00000)Metaspace       used 3293K, capacity 4564K, committed 4864K, reserved 1056768Kclass space    used 361K, capacity 388K, committed 512K, reserved 1048576K
SymbolTable statistics:
Number of buckets       :     20011 =    160088 bytes, avg   8.000
Number of entries       :     13355 =    320520 bytes, avg  24.000
Number of literals      :     13355 =    594648 bytes, avg  44.526
Total footprint         :           =   1075256 bytes
Average bucket size     :     0.667
Variance of bucket size :     0.668
Std. dev. of bucket size:     0.817
Maximum bucket size     :         6
StringTable statistics:
Number of buckets       :     60013 =    480104 bytes, avg   8.000
Number of entries       :      1745 =     41880 bytes, avg  24.000
Number of literals      :      1745 =    177296 bytes, avg 101.602
Total footprint         :           =    699280 bytes
Average bucket size     :     0.029
Variance of bucket size :     0.029
Std. dev. of bucket size:     0.171
Maximum bucket size     :         2

重点观察其中的StringTable statistics

1.创建100个字符串(不会触发垃圾回收)

public class Demo {public static void main(String[] args) throws InterruptedException {int i = 0;try {for (int j = 0; j < 100; j++) { // j=100, j=10000,100000String.valueOf(j).intern();i++;}} catch (Throwable e) {e.printStackTrace();} finally {System.out.println(i);}`}
}

打印

StringTable statistics:
Number of buckets       :     60013 =    480104 bytes, avg   8.000
Number of entries       :      1845 =     44280 bytes, avg  24.000
Number of literals      :      1845 =    182096 bytes, avg  98.697
Total footprint         :           =    706480 bytes
Average bucket size     :     0.031
Variance of bucket size :     0.031
Std. dev. of bucket size:     0.175
Maximum bucket size     :         2

可以发现Number of entries与Number of literals新增了100个字符串对象

2.创建10000个字符串(触发垃圾回收)

[GC (Allocation Failure) [PSYoungGen: 2048K->488K(2560K)] 2048K->786K(9728K), 0.0359746 secs] [Times: user=0.00 sys=0.00, real=0.04 secs] 
10000
HeapPSYoungGen      total 2560K, used 851K [0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)eden space 2048K, 17% used [0x00000000ffd00000,0x00000000ffd5ac98,0x00000000fff00000)from space 512K, 95% used [0x00000000fff00000,0x00000000fff7a020,0x00000000fff80000)to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)ParOldGen       total 7168K, used 298K [0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)object space 7168K, 4% used [0x00000000ff600000,0x00000000ff64a8b0,0x00000000ffd00000)Metaspace       used 3296K, capacity 4564K, committed 4864K, reserved 1056768Kclass space    used 361K, capacity 388K, committed 512K, reserved 1048576K
SymbolTable statistics:
Number of buckets       :     20011 =    160088 bytes, avg   8.000
Number of entries       :     13356 =    320544 bytes, avg  24.000
Number of literals      :     13356 =    594664 bytes, avg  44.524
Total footprint         :           =   1075296 bytes
Average bucket size     :     0.667
Variance of bucket size :     0.668
Std. dev. of bucket size:     0.817
Maximum bucket size     :         6
StringTable statistics:
Number of buckets       :     60013 =    480104 bytes, avg   8.000
Number of entries       :      8582 =    205968 bytes, avg  24.000
Number of literals      :      8582 =    505552 bytes, avg  58.908
Total footprint         :           =   1191624 bytes
Average bucket size     :     0.143
Variance of bucket size :     0.154
Std. dev. of bucket size:     0.393
Maximum bucket size     :         3

因为创建的字符串对象没有被引用,所以无用的字符串被垃圾回收

StringTable 性能调优

原理:StringTable底层是一个hash表,哈希桶越多,元素越分散,哈希碰撞的几率变小,查找速度会变快

1.调整StringTable哈希桶个数参数:调整 -XX:StringTableSize=桶个数

注意:设置桶个数小于1009时会报错

Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
StringTable size of 200 is invalid; must be between 1009 and 2305843009213693951

设置参数
-Xms500m -Xmx500m -XX:+PrintStringTableStatistics -XX:StringTableSize=200000

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 Demo {public static void main(String[] args) throws IOException {//linux.words中大约有48万个单词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("读取文件花费时间为:" + (System.nanoTime() - start) / 1000000);}}
}

注意:垃圾回收只有在内存紧张时才会触发

打印

读取文件花费时间为:191
SymbolTable statistics:
Number of buckets       :     20011 =    160088 bytes, avg   8.000
Number of entries       :     13359 =    320616 bytes, avg  24.000
Number of literals      :     13359 =    594752 bytes, avg  44.521
Total footprint         :           =   1075456 bytes
Average bucket size     :     0.668
Variance of bucket size :     0.668
Std. dev. of bucket size:     0.818
Maximum bucket size     :         6
StringTable statistics:
Number of buckets       :    200000 =   1600000 bytes, avg   8.000
Number of entries       :    481489 =  11555736 bytes, avg  24.000
Number of literals      :    481489 =  29750392 bytes, avg  61.788
Total footprint         :           =  42906128 bytes
Average bucket size     :     2.407
Variance of bucket size :     2.420
Std. dev. of bucket size:     1.556
Maximum bucket size     :        12

设置参数
-Xms500m -Xmx500m -XX:+PrintStringTableStatistics -XX:StringTableSize=1009


读取文件花费时间为:3685
SymbolTable statistics:
Number of buckets       :     20011 =    160088 bytes, avg   8.000
Number of entries       :     15965 =    383160 bytes, avg  24.000
Number of literals      :     15965 =    682432 bytes, avg  42.746
Total footprint         :           =   1225680 bytes
Average bucket size     :     0.798
Variance of bucket size :     0.794
Std. dev. of bucket size:     0.891
Maximum bucket size     :         6
StringTable statistics:
Number of buckets       :      1009 =      8072 bytes, avg   8.000
Number of entries       :    482761 =  11586264 bytes, avg  24.000
Number of literals      :    482761 =  29845656 bytes, avg  61.823
Total footprint         :           =  41439992 bytes
Average bucket size     :   478.455
Variance of bucket size :   432.022
Std. dev. of bucket size:    20.785
Maximum bucket size     :       547

可以看到StringTableSize变小后,向StringTable放入字符串的时间明显变长了

2.考虑将字符串对象是否入池

当有大量重复的字符串时,可以考虑使用intern()放入串池,减少字符串对象个数,节约内存


http://www.dtcms.com/wzjs/272151.html

相关文章:

  • 如何提高网站文章收录百度搜索引擎属于什么引擎
  • 做网站的html代码格式seo专员是做什么的
  • 安徽集团网站建设电商培训视频教程
  • 加盟网站制作定制新网站怎么快速收录
  • 好的网站具备的条件清理优化大师
  • 西宁市网站建设多少钱推广赚钱平台
  • 审计实务网站建设论文日本预测比分
  • 如何利用网站做demo产品推广策略怎么写
  • 付费做网站关键词优化是怎么做的呀郑州网站推广公司电话
  • 邢台企业做网站价格建立网站要多少钱一年
  • 黄山网站设计免费外链网站seo发布
  • 连云港网站建设公司有创意的网络营销案例
  • 张家港网站制作淘宝引流推广怎么做
  • wordpress lover主题淘宝seo搜索排名优化
  • 如何用模板做网站外贸营销网站制作公司
  • 电商网站建设实训总结谷歌seo代运营
  • 做淘宝客网站用什么系统吗seo关键词
  • 邢台网站建设优化怎么网站推广
  • 网站建设优秀网商丘网络推广公司
  • 简述商业网站建设的流程青岛关键词优化平台
  • 郑州网站制作开发百度教育官网
  • 山东大型网站建设百度首页纯净版怎么设置
  • 做商贸网站网络推广文案怎么写
  • app store官网北京seo培训
  • deramweaver做网站怎么在百度上做公司网页
  • 手机网站设计立找亿企邦陕西网络营销优化公司
  • 商标设计logo免费生成器网站电商数据网站
  • 做家政服务网站优化关键词软件
  • 做网站能挣钱吗百度手机助手应用商店
  • 网站会对特殊的ip做跳转2022年7到8月份的十大新闻