java String 最长长度和占用内存大小
一 序
String在内存中的最大长度理论上是int型变量的最大值,Integer.MAX_VALUE,
String的字面常量的最大长度为CONSTANT_Utf8_info表决定,一般为65535.
二 介绍
1、String的内部实现
通过一个字符数组来维护字符序列,其声名如下:
private final char value[];
2
所以,String的最大长度取决于字符数组的最大长度,因为字符数组长度只能是byte,char,short,int而不能是long型,所以这也说明最大长度,另一方面,我们知道String类有一个方法,str.length() 它的返回值是int型变量,声明如下:
public int length()
3
所以这也说明了最大长度的理论值,但在实际中,要比理论值小,
public class mainClass { public static void main(String[] args) {
// TODO Auto-generated method stub
char[] value=new char[Integer.MAX_VALUE];
System.out.println("");
}
}
这个错误是内存溢出错误,所以系统无法分配这么大的内存空间。
现在的问题是,计算机系统可以分配多大的内存呢?
三 分析源码
java.lang.String.java
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
java String类以char[]数组存储字符元素,因而,String类的最大长度实际上取决于char[]数组能够包含的数组长度。
我们可以简单做下试验,看看char[]数组的最大长度MAX_LENGTH是多少。
当我们将len值调到320339961的时候,系统刚刚好报错,
因此,char[]数组的最大长度可以达到 320339960,约为2^28.255,每个字符占用空间2个字节,也就是2^28.255字节,而4个G等于2^30字节。
因而char[]数组的最大长度约等于(不到)4个G。
String类型的长度为320339960,其最大容量不超过4个G。
String内部是以char数组的形式存储,数组的长度是int类型,那么String允许的最大长度就是Integer.MAX_VALUE了。又由于java中的字符是以16位存储的,因此大概需要4GB的内存才能存储最大长度的字符串。不过这仅仅是对字符串变量而言,如果是字符串字面量(string literals),如“abc"、"1a2b"之类写在代码中的字符串literals,那么允许的最大长度取决于字符串在常量池中的存储大小,也就是字符串在class格式文件中的存储格式:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
u2是无符号的16位整数,因此理论上允许的string literal的最大长度是2^16-1=65535。然而实际测试表明,允许的最大长度仅为65534
四 不同运行阶段分析
编译期
首先,我们先来合理的推断一下,当我们在代码中使用String s = “”;的形式来定义String对象的时候,""中字符的个数有没有限制呢?
既然是合理的推断,那就要要足够的依据,所以我们可以从String的源码入手,根据public String(char value[], int offset, int count)的定义,count是int类型的,所以,char value[]中最多可以保存Integer.MAX_VALUE个,即2147483647字符。(jdk1.8.0_73)
但是,实验证明,String s = “”;中,最多可以有65534个字符。如果超过这个个数。就会在编译期报错。
public static void main(String[] args) {String s = "a...a";// 共65534个aSystem.out.println(s.length());String s1 = "a...a";// 共65535个aSystem.out.println(s1.length());
}
以上代码,会在String s1 = “a…a”;// 共65535个a处编译失败:
✗ javac StringLenghDemo.java
StringLenghDemo.java:11: 错误: 常量字符串过长
明明说好的长度限制是2147483647,为什么65535个字符就无法编译了呢?
CONSTANT_Utf8_info {u1 tag;u2 length;u1 bytes[length];
}
The length of field and method names, field and method descriptors, and other constant string values is limited to 65535 characters by the 16-bit unsigned length item of the CONSTANTUtf8info structure (§4.4.7). Note that the limit is on the number of bytes in the encoding and not on the number of encoded characters. UTF-8 encodes some characters using two or three bytes. Thus, strings incorporating multibyte characters are further constrained.
也就是说,在Java中,所有需要保存在常量池中的数据,长度最大不能超过65535,这当然也包括字符串的定义。
运行期
2^31-1 =2147483647 个 16-bit Unicodecharacter2147483647 * 16 = 34359738352 位
34359738352 / 8 = 4294967294 (Byte)
4294967294 / 1024 = 4194303.998046875 (KB)
4194303.998046875 / 1024 = 4095.9999980926513671875 (MB)
4095.9999980926513671875 / 1024 = 3.99999999813735485076904296875 (GB)
五 占用内存大小
1、先介绍一下String对象的内存占用
JDK7:
private final char value[];
private int hash;
private transient int hash32;
对象头(8 字节)+ char 数组(16 字节)+ 3 个 int(3 × 4 = 12 字节)+1 个 char 数组的引用 (4 字节 ) = 40 字节。
8*( ( 8+12+2*n+4+12)+7 ) / 8 = 8*(int) ( ( ( (n) *2 )+43) /8 )
2、举个例子:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
private String strempty = new String();
public static void main(String[] args) throws Exception
TestBigString obj = new TestBigString();
obj.strsub = obj.readString().substring(0,1);
private String readString() throws Exception
StringBuilder sb = new StringBuilder();
while((line = bis.readLine()) != null)
System.out.println(sb.length());
其中文件"d:\\teststring.txt"里面有33475740个字符,文件大小有35M。
用JDK6来运行上面的代码,可以看到strsub只是substring(0,1)只取一个,count确实只有1,但其占用的内存却高达接近67M。
然而用JDK7运行同样的上面的代码,strsub对象却只有40字节
public String substring(int beginIndex, int endIndex) {
throw new StringIndexOutOfBoundsException(beginIndex);
throw new StringIndexOutOfBoundsException(endIndex);
throw new StringIndexOutOfBoundsException(endIndex - beginIndex);
return ((beginIndex == 0) && (endIndex == count)) ? this :
new String(offset + beginIndex, endIndex - beginIndex, value);
// Package private constructor which shares value array for speed.
String(int offset, int count, char value[]) {
public String substring(int beginIndex, int endIndex) {
throw new StringIndexOutOfBoundsException(beginIndex);
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
int subLen = endIndex - beginIndex;
throw new StringIndexOutOfBoundsException(subLen);
return ((beginIndex == 0) && (endIndex == value.length)) ? this
: new String(value, beginIndex, subLen);
public String(char value[], int offset, int count) {
throw new StringIndexOutOfBoundsException(offset);
throw new StringIndexOutOfBoundsException(count);
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
this.value = Arrays.copyOfRange(value, offset, offset+count);
可以看到原来是因为JDK6的String.substring()所返回的 String 仍然会保存原始 String的引用,所以原始String无法被释放掉,因而导致了出乎意料的大量的内存消耗。
String newString = new String(smallString.toCharArray());
C、同样,再看看split方法
private String strempty = new String();
public static void main(String[] args) throws Exception
TestBigString obj = new TestBigString();
obj.strsub = obj.readString().substring(0,1);
obj.strSplit = obj.readString().split("Address:",5);
JDK6中分割的字符串数组中,每个String元素占用的内存都是原始字符串的内存大小(67M):
而JDK7中分割的字符串数组中,每个String元素都是实际的内存大小:
public String[] split(String regex, int limit) {
return Pattern.compile(regex).split(this, limit);
public String[] split(CharSequence input, int limit) {
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<String>();
// Add segments before each match found
if (!matchLimited || matchList.size() < limit - 1) {
String match = input.subSequence(index, m.start()).toString();
public CharSequence subSequence(int beginIndex, int endIndex) {
return this.substring(beginIndex, endIndex);
4、其他方面:
1、String a1 = “Hello”; //常量字符串,JVM默认都已经intern到常量池了。
创建字符串时 JVM 会查看内部的缓存池是否已有相同的字符串存在:如果有,则不再使用构造函数构造一个新的字符串,
直接返回已有的字符串实例;若不存在,则分配新的内存给新创建的字符串。
String a2 = new String(“Hello”); //每次都创建全新的字符串
2、在拼接静态字符串时,尽量用 +,因为通常编译器会对此做优化。
return "str1" + "str2" + "str3";
0: ldc #24; //String str1str2str3 --将字符串常量压入栈顶
public String constractStr(String str1, String str2, String str3)
对应字节码(JDK1.5之后转换为调用StringBuilder.append方法):
0: new #24; //class java/lang/StringBuilder
5: invokestatic #26; //Method java/lang/String.valueOf:(Ljava/lang/Objec
8: invokespecial #32; //Method java/lang/StringBuilder."<init>":(Ljava/la
12: invokevirtual #35; //Method java/lang/StringBuilder.append:(Ljava/lang
/String;)Ljava/lang/StringBuilder;
16: invokevirtual #35; //Method java/lang/StringBuilder.append:(Ljava/lang
/String;)Ljava/lang/StringBuilder; ――调用StringBuilder的append方法
19: invokevirtual #39; //Method java/lang/StringBuilder.toString:()Ljava/l
详解Java的自动装箱与拆箱(Autoboxing and unboxing) - 低调的小白 - 博客园
Java中String接受的最大字符串的长度是多少_一往无前-千夜的博客-CSDN博客_java string长度是多少个字节
https://www.iteye.com/blog/lin-yp-168367
java String 最长长度和占用内存大小相关推荐
- Java 中对象占用内存大小计算
原文地址 mp.weixin.qq.com byte 与 bit bit:位,比特.信息的最小单位,二进制数中的一个位数 (二进制位),其值为"0" 或"1": ...
- 面试官上来就问:Java 进程中有哪些组件会占用内存?
本文的内容来自 StackOverflow 的一个问答:Java using much more memory than heap size (or size correctly Docker mem ...
- android 图片占用内存大小及加载解析
*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布 在讲解图片占用内存前,我们先问自己几个问题: 我们在对手机进行屏幕适时,常想可不可以只切一套图适配所有的手机呢? 一张图片加载到手 ...
- android bitmap 占用内存大小,drawable与bitmap内存占用大小
1, 比较Drawable与Bitmap占用内存大小 2, 比较BitmapFactory类的decodeResource方法与decodeStream方法的效率 好吧,先来看第1个测试! 以下这个是 ...
- 安卓中图片占用内存大小分析
相关概念: 位深 色彩空间 颜色通道 int型占用字节 位深: 位是二进制的位.位深是指计算机系统中图片的一个像素点占用的二进制位数.例如位深32,就是使用2^8 = 32 位二进制来表示像素值.例如 ...
- 安卓图片内存优化(一)——图片占用内存大小的计算
安卓开发中经常会遇到因为图片处理不当导致的oom问题,因为系统分配给每个应用的最大内存空间是有限的,正常只有几十上百兆(排除通过特殊手段获取到几百兆内存空间的情况).所以为了节省更多的空间需要对图片进 ...
- linux查看进程占用的内存大小,查看进程占用内存大小的几种方法,占用内存几种方法...
查看进程占用内存大小的几种方法,占用内存几种方法 1. pmap -x pid 2. ps -aux | grep 进程名 ps -e -o 'pid,comm,args,pcpu,rsz,vsz,s ...
- Java 对象占用内存大小
Java 对象 如果想要了解java对象在内存中的大小,必须先要了解java对象的结构. HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header).实例数据(Instan ...
- Java String 的最大长度
最近在处理一个问题时,需要把正式环境的一大段文本复制到Idea中写测试类,结果复制后报"常量字符串过长"的错误,上网一查,才对Java String有了更多的了解.主要是2个方面: ...
最新文章
- 通用权限管理系统组件 中集成多个子系统的单点登录(网站入口方式)附源码
- 关卡设计快速入门_2. 导航视口
- No new data sinks have been defined since the last execution.
- 同步和异步有何异同,什么场景使用
- 初涉c#设计模式-Iterator Pattern
- FFMPEG中最关键的结构体之间的关系
- 关于 IIS7.0下文件写入无权限的解决办法
- 01. 仔细区分pointer和references
- React 混合中英文计算字符长度
- Godot简单的斜抛运动
- 理科生毕业,如何写论文,为论文降重
- C# 批量图片打包下载
- EndNoteX9保姆级基础功能使用教程(够用!!)
- E. Fruit Slicer--计算几何+两圆公切线
- IgA | 对抗病原菌,帮助共生菌定植的“重要开关”
- 【Godot 插件】获取编辑器上所有的节点
- 图形学扫描线填充算法
- el-upload点击打开文件上传弹窗之前进行其他操作,等待操作完成后再打开文件上传弹窗
- GVM(OpenVAS)创建扫描报错:Failed to find config ‘d21f6c81-2b88-4ac1-b7b4-a2a9f2ad4663‘解决方法
- ChatGPT解开了我一直以来对自动化测试的疑惑