`
azvf
  • 浏览: 147089 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

String那点事儿2--占了多少空间

阅读更多

本文部分内容摘抄自:《算法》第四版,图灵丛书,人邮出版社

孔老师:茴香豆的茴字有四种写法,来,我告诉你。

1、一道面试题

String str = "搞java";占用多少内存空间?一般给的答案是“6字节”。然而凭着男人的直觉,这个答案貌似不完全正确。

如下图示:

 

这6个字节是如何来的?看这里,上干货fuck goods

import java.io.UnsupportedEncodingException;
public class StringTest {
	public static void main(String[] args) throws UnsupportedEncodingException {
		String str = "搞java";
		System.out.println("\"搞java\".length():" + (str.length()));
		System.out.println("\"搞java\".getBytes().length:" + (str.getBytes().length));
		System.out.println("\"搞java\".getBytes(\"GBK\").length:" + (str.getBytes("GBK").length));
		System.out.println("\"搞java\".getBytes(\"UTF-8\").length:" + (str.getBytes("UTF-8").length));
		/**
		 *  "搞java".length():5
			"搞java".getBytes().length:6
			"搞java".getBytes("GBK").length:6
			"搞java".getBytes("UTF-8").length:7
		 */
	}
}

 

 6个字节的来源是getByte().length。

 

2、看源码解释方法

String.length()方法,返回一个和该字串的uinicode单位数量相同的长度,就是字串的长度。"搞java"中一共有5个单位的unicode码,返回5,注意这个方法并不是该字串所占用的存储空间

    /**
     * Returns the length of this string.
     * The length is equal to the number of <a href="Character.html#unicode">Unicode
     * code units</a> in the string.
     *
     * @return  the length of the sequence of characters represented by this
     *          object.
     */
    public int length() {
        return count;
    }

 String.getBytes()方法,使用平台默认字符集,将该字串编码成字节序列,将结果搞到一个byte数组中。是的,是平台默认字符集,也就是不同的字符集,将会产生不同的字节序列。"GBK"编码中,1个汉字2个字节,一个ASC2是1个字节,"搞java"是6个byte;"utf-8"码中,1个汉字将占用3个字节,1个ASC2是1个字节,"搞java"就是7个byte

    /**
     * Encodes this {@code String} into a sequence of bytes using the
     * platform's default charset, storing the result into a new byte array.
     *
     * <p> The behavior of this method when this string cannot be encoded in
     * the default charset is unspecified.  The {@link
     * java.nio.charset.CharsetEncoder} class should be used when more control
     * over the encoding process is required.
     *
     * @return  The resultant byte array
     *
     * @since      JDK1.1
     */
    public byte[] getBytes() {
	return StringCoding.encode(value, offset, count);
    }

 

结论:length()方法不能表示占用存储空间;getByte()方法和平台默认字符集有关不靠谱,"GBK"字符集下将会编码成6个byte,其他字符集就未必了。

 

3、真相极其残酷,String对象所占的内存空间

3.1、对象所使用的空间,

•对象头(object header):32位机8 个字节(保存对象的 class 信息、ID、在虚拟机中的状态),64位机器16字节

•Java 原始类型数据:如 int, float, char 等类型的数据,参看表1

•引用(reference):在32位系统上每个占用4bytes, 在64位系统上每个占用8bytes

•填充符(padding):一般内存的使用会被填充为8的倍数

表 1. Java 各数据类型所占内存
数据类型占用内存(字节数)
boolean 1
byte
char 2
short
int 4
float
long 8
double

3.2数组所占用内存空间

java中数组被实现为对象,因为记录长度而需要额外的内存。一个原始数据类型的数组一般需要24字节头信息(16个字节的对象开销,4字节保存长度,4字节填充字)再加上保存值所需要的内存。例如:1个N个int的数组,需要使用(24+4N)字节,一个int占4字节;一个含有N个double的数组,需要(24+8N),一个double占8字节;

 

3.3空字串所占内存空间

如果对于 String(JDK 6)的成员变量声明如下:

  private final char value[]; 
  private final int offset; 
  private final int count; 
  private int hash;

如何计算该 String 所占的空间?String对象内存+3个int属性内存+1个char[]内存,就是这么计算

先计算空的 char 数组所占空间:

<64位机>16(对象开销)+ 4(保存长度) + 2*0(一个char是2字节,共有0个char)=20byte,再给padding使之成为8的倍数,就是20 + 4 = 24字节 

<32位机>8(对象开销) + 4 (保存长度) + 2*0=12字节,填充一下就是12+4=16 字节

 

那么一个空 String 所占空间为:

<64位机>16(对象开销) + 12字节(3个int,1个int占4字节) + 8(char[]引用) + 24(空char[]) = 60字节

不要忘了填充,60 + 4 = 64字节

<32位机>8(对象开销) + 12字节(3个int) + 4(char[]引用) + 16(空char[]) = 40字节

 

结论,String对象所占内存空间大约为

N是String对象char数组的长度,注意这里说的的char[]数组的长度,而不是String.length()

<64位机> 2*N + 64 + padding,这么多的字节byte

<32位机> 2*N + 40 + padding,这么多的字节byte

现在回过头来看面试题,String str = "搞java";占用多少内存空间?一般给的答案是“6字节”。然而这个答案一定完全不正确。

 

结束的时候,留一个悬疑,敬请关注下篇:String那点事儿3--溢出、陷阱、效率、优化

 

 String那点事儿1--创建了几个对象

String那点事儿2--占了多少空间

String那点事儿3--溢出、陷阱、效率、优化 

  • 大小: 5.9 KB
  • 大小: 381.9 KB
分享到:
评论
3 楼 greatwqs 2016-07-02  
这样的帖子必须手动来赞一个!   
2 楼 azvf 2013-12-09  
wahely 写道
发现博主有几片博文都是错误的,我想博主应该也是一片好心,但小心误人子弟啊。
看到这篇了说一下:
<32位机> 2*N + 40,这么多的字节byte 2*5+40=50 这个答案明显是错误的,padding没有考虑进去,所以说必须是8的倍数。
正确答案应该是:8(对象开销) + 12字节(3个int) + 4(char[]引用) + 24(搞java char[]:头8+length 4+ value 10 + padding 2) = 48


1、感谢你的关注
2、结论已经修改为
<64位机> 2*N + 64 + padding,这么多的字节byte
<32位机> 2*N + 40 + padding,这么多的字节byte
1 楼 wahely 2013-12-09  
发现博主有几片博文都是错误的,我想博主应该也是一片好心,但小心误人子弟啊。
看到这篇了说一下:
<32位机> 2*N + 40,这么多的字节byte 2*5+40=50 这个答案明显是错误的,padding没有考虑进去,所以说必须是8的倍数。
正确答案应该是:8(对象开销) + 12字节(3个int) + 4(char[]引用) + 24(搞java char[]:头8+length 4+ value 10 + padding 2) = 48

相关推荐

Global site tag (gtag.js) - Google Analytics