2010-01-27 39 views
6

Tengo un archivo desde el que leo datos. Todo el texto de este archivo se almacena en una variable String (una variable muy grande). Luego, en otra parte de mi aplicación, quiero recorrer esta cadena y extraer información útil, paso a paso (analizando la cadena).Cómo lidiar con cadenas grandes y memoria limitada

Mientras tanto, mi memoria se llena y una excepción OutOfMemory me impide el procesamiento posterior. Creo que sería mejor procesar los datos directamente mientras se lee la ruta de entrada desde el archivo. Pero para fines de organización, me gustaría pasar el String a otra parte en mi solicitud.

¿Qué debo hacer para evitar que la memoria se desborde?

+0

¿No puedes analizar el archivo bit a bit con uno de los lectores (por ejemplo, BufferedReader)? –

Respuesta

7

Debe utilizar el BufferedInputReader en lugar de almacenar todo esto en una cadena grande.

Si lo que quiere analizar se encuentra en la misma línea, entonces StringTokenizer funcionará muy bien, de lo contrario deberá idear una forma de leer lo que quiere del archivo para analizar las declaraciones, luego aplique StringTokenizer a cada una declaración.

+0

+1. Anthony: la idea general es que pases CURSORES (como en DB). Pueden ser Lectores en caso de texto, Secuencias en caso de bytes, iteradores en caso de secuencia de elementos, o lo que sea. Puede transformar un tipo en otro (transformar cada elemento de la secuencia, por ejemplo, una línea en el archivo en algún objeto de dominio) pero lo que un área de la aplicación proporciona a otro es un cursor, por lo que es un buen control para consumir el ingrese un paso a la vez sin incurrir en el conocimiento de leer archivos o cualquier transformación que implemente en el medio. – helios

+0

Los enlaces que ha proporcionado de 'BufferedInputReader' y' StringTokenizer' no están disponibles. – Root

6

Si puede aflojar un poco sus requisitos, podría implementar un java.lang.CharSequence respaldado por su archivo.

La secuencia de caracteres es compatible con many places in the JDK (Una cadena es una secuencia de caracteres Char). Entonces esta es una buena alternativa a una implementación basada en Reader.

1

Debe revisar su algoritmo para manejar datos de gran tamaño. Debe procesar los datos por fragmentos o utilizar el acceso aleatorio a archivos sin almacenar datos en la memoria. Por ejemplo, puede usar StringTokenizer o StreamTokenizer como dijo @Zombies. Puede ver las técnicas de analizador-analizador: cuando el analizador analiza alguna expresión, solicita lexer para leer el siguiente lexema (tokens), pero no lee todo el flujo de entrada a la vez.

4

Otros han sugerido leer y procesar partes de su archivo a la vez. Si es posible, una de esas formas sería mejor.

Sin embargo, si esto no es posible y puede cargar el String inicialmente en la memoria como lo indica pero es más tarde el análisis de esta cadena que crea problemas, es posible que pueda utilizar subcadenas. En Java, una subcadena se correlaciona con la matriz original char y solo toma la memoria para la base Object y luego los punteros int de inicio y de longitud.

Por lo tanto, cuando se encuentra una porción de la cadena que desea mantener por separado, usar algo como:

String piece = largeString.substring(foundStart, foundEnd); 

Si en lugar de esto o código que internamente hace esto, entonces el uso de memoria aumentará dramáticamente :

new String(largeString.substring(foundStart, foundEnd)); 

Tenga en cuenta que debe utilizar String.substring() con cuidado por esta misma razón. Puede tener una secuencia muy grande de la cual toma una subcadena y luego descarta su referencia a la cadena original. El problema es que la subcadena todavía hace referencia a la gran matriz original char. El GC no lo lanzará hasta que la subcadena también se elimine. En casos como este, es útil usar realmente new String(...) para asegurar que la matriz grande no utilizada será descartada por el GC (este es uno de los pocos casos donde debe usar new String(...)).

Otra técnica, si espera tener muchas cuerdas pequeñas y estas tienen los mismos valores, pero vienen de una fuente externa (como un archivo), es usar .intern() después de crear la nueva cadena.

Nota: Esto depende de la implementación de String que realmente no debería tenerse en cuenta, pero en la práctica para aplicaciones grandes a veces tiene que confiar en ese conocimiento. Tenga en cuenta que las versiones futuras de Java pueden cambiar esto (aunque no es probable).

Cuestiones relacionadas