java cadena de longitud más larga y tome tamaño de la memoria

uno de los mecanismos


Cadena teóricamente longitud máxima es el valor máximo en la memoria del tipo int, Integer.MAX_VALUE,
la longitud máxima de la mesa literal de cadena se determina CONSTANT_Utf8_info, típicamente 65.535.

II presenta


1, la cadena interior implementados
para mantener la secuencia de caracteres por una matriz de caracteres, su fama como sigue:

valor Char final privado [];
2
Por lo tanto, la longitud máxima depende de la longitud máxima de la matriz de caracteres String, porque la longitud de caracteres de la matriz es solamente byte, char, short, tipo int no puede ser largo, lo que también muestra la longitud máxima, el otro Por un lado, sabemos que la clase String tiene un método, str.length valor de retorno () de su variable de tipo int, la siguiente declaración:

longitud público int ()
. 3
por lo que este también explica la longitud máxima de la teoría, pero en la práctica, a menos que el valor teórico,

public class MainClass {void (String [] args) {public static principal
        // generada-Auto TODO método stub
        char [] Valor = new char [Integer.MAX_VALUE];   
        System.out.println ( "");
    }

}

Este error es un error de desbordamiento de la memoria, por lo que el sistema no puede asignar un espacio de memoria tan grande.
La pregunta ahora es, el sistema informático puede asignar la cantidad de memoria?
 

El análisis de tres - fuente

 

java.lang.String.java

public String clase final
    los implementos del java.io.Serializable, la Comparable <String>, {CharSequence
    / ** Se utiliza para el personaje del valor es * Almacenamiento /.
    valor carácter privado última [];
la clase String de Java a char [] elemento de la matriz tiendas de carácter, por lo tanto, la longitud máxima de la clase String de hecho depende char [] matriz contiene la longitud de la matriz es posible.
Simplemente podemos hacer la siguiente prueba para ver si la longitud char [] gama máxima de MAX_LENGTH es.
Cuando transferimos 320 339 961 Valor len, el sistema acaba de error correcto,


Por lo tanto, char [] matriz puede alcanzar una longitud máxima de 320 339 960, aproximadamente 2 ^ 28.255, un espacio para cada byte carácter, es decir, 2 ^ 28.255 bytes, y 4 bytes de G es igual a 2 ^ 30.

Por lo tanto char [] array es aproximadamente igual a la longitud máxima (menor que) 4 G.

tipo String 320 339 960 longitud, la capacidad máxima de no más de 4 G.

 

 

Cadena se almacena como una matriz de caracteres interna, la longitud de la matriz es de tipo int, String es la longitud máxima permitida por el Integer.MAX_VALUE. También, porque el personaje es java de memoria de 16 bits, por lo que probablemente necesita una cadena de 4 GB de memoria para almacenar la longitud máxima. Pero esto es sólo una variable de caracteres, si la cadena literal (literales de cadena), tales como "abc", "1a2b" y similares escrito en la cadena de código de literales, entonces la longitud máxima permitida cadena depende en el tamaño de almacenamiento de la piscina constante, que es el formato de cadena se almacena en el formato de archivo de clase:

CONSTANT_Utf8_info {
        tag u1;
        longitud u2;
        u1 bytes [longitud];
}


    u2 es un entero sin signo de 16 bits, un literal de cadena es, por tanto teóricamente posible longitud máxima es de 65 535 = 2 ^ 16-1. Sin embargo, pruebas reales muestran que la longitud máxima permitida sólo 65.534

Cuatro etapas de funcionamiento diferentes de análisis

 

Compilar

En primer lugar, vamos a echar un inferencias razonables acerca de cuando usamos el código String s = ""; objeto String para definir la forma del tiempo "" el número de caracteres que hay un límite a la misma?
Dado que es una inferencia razonable, que tendría que ser base suficiente, por lo que se puede partir de la fuente de cuerdas, de acuerdo con public String (valor char [], int offset, int count) se define, el recuento es de tipo int, por lo tanto, char valor [] se puede ahorrar hasta un Integer.MAX_VALUE, a saber 2147483647 caracteres. (Jdk1.8.0_73)
Sin embargo, los experimentos muestran, String s = "";, que puede tener hasta 65.534 caracteres. Si se supera este número. Será error en tiempo de compilación.

public static void main(String[] args) {

    String s = "a...a";// 共65534个a
    System.out.println(s.length());

    String s1 = "a...a";// 共65535个a
    System.out.println(s1.length());
}

 

El código anterior será en cadena s1 = "a un ..."; // un total de 65.535 durante la compilación falló:

✗ javac StringLenghDemo.java
StringLenghDemo.java:11: 错误: 常量字符串过长

 

Es claro que un límite de longitud es buena 2147483647, ¿por qué 65535 caracteres no serán capaces de compilación?

Cuando usamos los literales de cadena definen directamente una cuerda, la cuerda estará en una piscina constante de almacenamiento. 65534 entonces el hecho antes mencionado es limitar la piscina constante.
Cada elemento de datos en la piscina constante también tiene su propio tipo. Codificación UTF-8 de Unicode en una cadena tipo Java CONSTANT_Utf8 representado en la piscina constante.
Tipo CONSTANTUtf8info CONSTANTUtf8 es una constante de elementos de datos de la piscina, que es una constante de cadena se almacena. Toda la piscina constante literal casi siempre son descritos por CONSTANTUtf8info. CONSTANTUtf8_info define como sigue:

CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
}

 

Dado que el objetivo de este artículo no es CONSTANTUtf8info introducción, no se inician aquí en detalle, y sólo tenemos que utilizar nuestra literal de cadena se definen en el archivo de clase se almacena utilizando CONSTANTUtf8info y CONSTANTUtf8info tener una longitud u2; indicar el tipo la longitud de los datos almacenados.
u2 es un enteros sin signo de 16 bits, la longitud máxima permitida es teóricamente 2 ^ 16 = 65 536. Y el archivo de clase Java es un formato de codificación UTF-8 a la variante tienda de personajes con valores nulos, utilizando dos bytes para representar, dejando así 65536-2 = 65534 bytes.
En este sentido, en la especificación de formato de archivo de clase también se indica claramente:

La longitud del campo y método de nombres, descriptores de campo y método, y otros valores de cadena constantes se limita a 65535 caracteres por el elemento de longitud sin signo de 16 bits de la estructura CONSTANTUtf8info (§4.4.7). Tenga en cuenta que el límite está en el número de bytes de la codificación y no en el número de caracteres codificados. UTF-8 codifica algunos caracteres utilizando dos o tres bytes. Por lo tanto, las cadenas de caracteres de varios bytes que incorporan son aún más limitada.

Es decir, en Java, todas las necesidades de datos que se guardan en la piscina constante, la longitud máxima no puede exceder de 65.535, lo que por supuesto también incluye la definición de la cadena.

Tiempo de ejecución

Cadena Esto limita la longitud de la limitación mencionada anteriormente del compilador, que se utiliza String s = ""; manera literal cuando esta definición será algunos límites.
Bueno. Cadena en tiempo de ejecución no tiene límite, la respuesta es que no Integer.MAX_VALUE que hemos mencionado antes, este valor es aproximadamente igual a 4G, en tiempo de ejecución, si la longitud de la cadena supera este intervalo, puede lanzar una excepción. (1.9 en vez de JDK)
int es un tipo variable de 32 bits, toma una parte número positivo para contar las palabras, pueden ser hasta

2^31-1 =2147483647 个 16-bit Unicodecharacter

2147483647 * 16 = 34359738352 位
34359738352 / 8 = 4294967294 (Byte)
4294967294 / 1024 = 4194303.998046875 (KB)
4194303.998046875 / 1024 = 4095.9999980926513671875 (MB)
4095.9999980926513671875 / 1024 = 3.99999999813735485076904296875 (GB)

El espacio de memoria de cinco 

1, primera decirnos sobre el consumo de memoria del objeto String

En general, los objetos Java en la configuración de máquina virtual es la siguiente:
• cabecera del objeto (cabecera de objeto): 8 bytes (para ahorrar clase información de objeto, ID, estado de la máquina virtual)
• los tipos de datos primitivos de Java: tales como int, float, char y otros tipos de datos
• una referencia (referencia): 4 bytes
• relleno (relleno)

Cadena de definición:

JDK6:
valor carácter privado final [];
int final privado compensado;
int cuenta final privado;
hash de private int;

JDK6 espacio ocupado por cadena vacía es de 40 bytes

JDK7:
valor carácter privado final [];
hash de private int;
hash32 int transitoria privado;

El espacio ocupado por la cadena vacía JDK7 es de 40 bytes

Calculado JDK6 huella de memoria de cadena:
primero calcular un Char vacío matriz ocupa espacio, sino también una matriz de objetos en Java, y por lo tanto hay una gran variedad de cabecera de objeto, es un espacio ocupado por una matriz de espacio ocupado por la cabeza objeto más un array longitud, es decir, 8 + 4 = 12 bytes, 16 bytes después del llenado.

A continuación, una cadena vacía ocupado el espacio:

cabecera del objeto (8 bytes) + matriz de caracteres (16 bytes) 3 + int (3 × 4 = 12 bytes) 1 Char referencia array (4 bytes) = 40 bytes.

Por lo tanto, una fórmula para el cálculo del espacio de cadena real ocupado por la siguiente:

8 * ((8 + 12 + 2 * n + 4 + 12) 7) / 8 = 8 * (int) ((((n) * 2) 43) / 8)

En donde, n es la longitud de la cadena.

2, por ejemplo:

A, substringA

paquete de demostración;

java.io.BufferedReader importación;

java.io.File importación;

java.io.FileInputStream importación;

java.io.InputStreamReader importación;

TestBigString clase pública

{

    strsub cadena privada;

    Cadena strempty privada = new String ();

    public static void Main (args String []) throws Exception

    {

        TestBigString obj = new TestBigString ();

        . Obj.strsub = obj.readString () subcadena (0,1);

        Hilo. sueño (30 * 60 * 1000);

    }

    Cadena readString privada () throws Exception

    {

        BufferedReader bis = null;

        tratar

        {

            bis = new BufferedReader (nuevo InputStreamReader (nuevo FileInputStream (nuevo archivo ( "D: \\ teststring.txt"))));

            StringBuilder sb = new StringBuilder ();

            línea de cadena = null;

            while ((línea = bis.readLine ())! = null)

            {

                sb.append (línea);

            }

            Sistema. fuera .println (sb.length ());

            volver sb.ToString ();

        }

        finalmente

        {

            si (bis! = null)

            {

                bis.close ();

            }

        }

    }

}

Cuando el archivo "D: \\ teststring.txt" hay 33,475,740 caracteres, 35M tamaño del archivo.

JDK6 uso para ejecutar el código anterior, se puede ver strsub simplemente subcadena (0,1) tarda sólo uno, contar realmente una sola, pero la cantidad de memoria era tan alto como casi 67M.

 

Sin embargo, la misma operación con los anteriores códigos JDK7, strsub el objeto es de sólo 40 bytes

 

B, lo que lo causa?

Mirar el código fuente del JDK:

JDK6:

public String substring (int beginIndex, int endIndex) {

    si (beginIndex <0) {

        arrojar nueva StringIndexOutOfBoundsException (beginIndex);

    }

    si (endIndex> count) {

        arrojar nueva StringIndexOutOfBoundsException (endIndex);

    }

    si (beginIndex> endIndex) {

        arrojar nueva StringIndexOutOfBoundsException (endIndex - beginIndex);

    }

    retorno ((beginIndex == 0) && (endIndex == recuento))? esta :

        nueva cadena (offset + beginIndex, endIndex - beginIndex, valor);

}

// Paquete constructor privado, que comparte valor de matriz para la velocidad.

    String (int offset, int cuenta, el valor char []) {

    this.value = valor;

    this.offset = offset;

    this.count = count;

}

JDK7:

public String substring (int beginIndex, int endIndex) {

        si (beginIndex <0) {

            arrojar nueva StringIndexOutOfBoundsException (beginIndex);

        }

        si (endIndex> value.length) {

            arrojar nueva StringIndexOutOfBoundsException (endIndex);

        }

        int subLen = endIndex - beginIndex;

        si (subLen <0) {

            arrojar nueva StringIndexOutOfBoundsException (subLen);

        }

        volver ((beginIndex == 0) && (endIndex == value.length))? esta

                : Nueva cadena (valor, beginIndex, subLen);

}

public String (valor char [], int offset, int cuenta) {

        si (offset <0) {

            arrojar nueva StringIndexOutOfBoundsException (offset);

        }

        si (recuento <0) {

            arrojar nueva StringIndexOutOfBoundsException (recuento);

        }

        // Nota: offset o recuento podrían estar cerca de -1 >>> 1.

        si (offset> value.length - recuento) {

            arrojar nueva StringIndexOutOfBoundsException (offset + recuento);

        }

        this.value = Arrays. copyOfRange (valor de offset, offset + recuento);

    }

JDK6 puede ver el original es a causa de String.substring () devuelto String String todavía mantiene una referencia a la original, por lo que la cadena original no puede ser liberado, lo que resulta en una gran cantidad de consumo de memoria de forma inesperada.

El propósito de este diseño es en realidad JDK6 con el fin de ahorrar memoria, ya que estos son multiplexadas con la cadena original de cuerdas, sino por el tipo int offerset, cuente el equivalente de una nueva cadena para identificar subcadena.

Sin embargo, para el ejemplo anterior, tomado de un pequeño número de gigante String String se utiliza en lo sucesivo, este diseño es causado por una gran cantidad de datos redundante. Así, las conclusiones con respecto a la operación tomada por el String.split String () o String.substring () como sigue:

• Para aplicaciones tomadas de una pequeña cadena de texto grande, String.substring () dará lugar a un derroche excesivo de la memoria.
• la suma de la longitud de la cadena de caracteres tomados de una serie de cadenas en el texto general, tomada de la longitud original de texto o menos, String.substring convencional () diseñado para exactamente el texto original puede ser compartida con el fin de alcanzar el objetivo de ahorro de memoria.

Desde el camino a la causa de una gran cantidad de espacio de memoria es String.substring () devuelve el resultado contiene una serie de cuerdas original, entonces una reducción en la memoria de los residuos es eliminar estos cadena original. La estructura de llamada newString que contiene sólo una cadena tomada de nuevo de cadena, se puede llamar String.toCharArray () Método:

Cadena newString = new String (smallString.toCharArray ());

C , del mismo modo, echar un vistazo a dividir método

TestBigString clase pública

{

    strsub cadena privada;

    Cadena strempty privada = new String ();

    privada String [] strSplit;

    public static void Main (args String []) throws Exception

    {

        TestBigString obj = new TestBigString ();

        . Obj.strsub = obj.readString () subcadena (0,1);

        obj.strSplit = obj.readString split () ( "Dirección:", 5);.

        Hilo. sueño (30 * 60 * 1000);

    }

JDK6 matriz dividida en las cadenas, el tamaño de la memoria de cada memoria es un elemento de cuerda ocupada de la cadena original (67M):

 

cadena JDK7 y dividido en matriz, cada elemento es el real tamaño de la cadena de memoria:

 

D, razones:

JDK6 Fuente:

public String [] división (expresión regular, limitar int) {

    Patrón volver. de compilación (regex) .split (esto, límite);

    }

public String [] dividida (entrada CharSequence, límite int) {

        int index = 0;

        boolean matchLimited = límite> 0;

        ArrayList <String> matchlist = new ArrayList <String> ();

        Matcher m = matcher (entrada);

        // Añadir segmentos antes de cada partido encontrado

        while (m.find ()) {

            if (! matchLimited || matchList.size () <límite - 1) {

                partido String = input.subSequence (índice, m.start ()) toString ().;

                matchList.add (juego);

pública CharSequence subsecuencia (int beginIndex, int endIndex) {

        retorno this.substring (beginIndex, endIndex);

    }

4. Otros aspectos:

1、String a1 = “Hello”; //常量字符串,JVM默认都已经intern到常量池了。
创建字符串时 JVM 会查看内部的缓存池是否已有相同的字符串存在:如果有,则不再使用构造函数构造一个新的字符串,
直接返回已有的字符串实例;若不存在,则分配新的内存给新创建的字符串。
String a2 = new String(“Hello”); //每次都创建全新的字符串

2, al empalmar una cadena estática, trate de usar +, ya que normalmente el compilador va a hacer esta optimización.

pública  Cadena constractStr ()

    {

        volver  "str1" + "str2" + "str3";

}

En correspondencia con el código de bytes:

Código:

0: LDC # 24; // Cadena str1str2str3 - constantes de cadena en la pila

2 areturn

3, las cuerdas dinámicas de corte y empalme, intenta utilizar la append StringBuffer o StringBuilder, reduciendo así excesiva construcción de un objeto String temporal (los compiladores javac hará optimizado automáticamente cadena de conexión):

pública  Cadena constractStr (String str1, Cadena str2, Cadena str3)

    {

        volver  str1 + str2 + str3;

}

(Después de la conversión de llamar al método StringBuilder.append JDK1.5) correspondiente al código de bytes:

Código:

0: nueva # 24; // clase java / lang / StringBuilder

3: después de

4: aload_1

5: invokestatic # 26; // Método java / lang / String.valueOf: (Ljava / lang / Objec

t;) Ljava / lang / cadena;

8: invokespecial # 32; // Método java / lang / StringBuilder. "<Init>" :( Ljava / La

de / cadena;) V

11: aload_2

12: invokevirtual # 35; // Método java / lang / StringBuilder.append: (Ljava / lang

/ Cadena;) Ljava / lang / StringBuilder;

15: aload_3

16: invokevirtual # 35; // Método java / lang / StringBuilder.append: (Ljava / lang

/ Cadena;) Ljava / lang / StringBuilder; - método append invocación de StringBuilder

19: invokevirtual # 39; // Método java / lang / StringBuilder.toString :() Ljava / l

El / cadena;

22: areturn - devuelve una referencia

 

observación 

boxeo automático y unboxing

https://www.cnblogs.com/wang-yaz/p/8516151.html

https://blog.csdn.net/wolfking0608/article/details/78583944

https://www.iteye.com/blog/lin-yp-168367

Publicado 43 artículos originales · ganado elogios 28 · Vistas a 40000 +

Supongo que te gusta

Origin blog.csdn.net/u013380694/article/details/102739636
Recomendado
Clasificación