que - substr javascript
Límite de tamaño de cadena de Javascript: 256 MB para mí: ¿es el mismo para todos los navegadores? (3)
Curioso acerca de cuál era la longitud máxima de cadena que podía obtener en Javascript, lo probé yo mismo, hoy, en mi Firefox 43.0.1, corriendo en Windows 7. Pude construir una cadena con longitud 2^28 - 1
, pero cuando Traté de crear una cadena con un carácter más, Firebug me mostró el error de "desbordamiento del tamaño de la asignación" , lo que significa que la cadena debe tener menos de 256 MB.
¿Es esto lo mismo para todos los navegadores, todas las computadoras, todos los sistemas operativos, o depende?
Creé el siguiente fragmento para descubrir el límite:
(function() {
strings = ["z"];
try {
while(true) {
strings.push(strings[strings.length - 1] + strings[strings.length - 1]);
}
} catch(err) {
var k = strings.length - 2;
while(k >= 0) {
try {
strings.push(strings[strings.length - 1] + strings[k]);
k--;
} catch(err) {}
}
console.log("The maximum string length is " + strings[strings.length - 1].length);
}
})();
Si está ejecutando un navegador / sistema operativo diferente, me gustaría ver sus resultados. Mi resultado fue La longitud máxima de la cadena es 268435455 .
PD: Busqué una respuesta, pero el tema más reciente que encontré fue de 2011, por lo que estoy buscando información más actualizada.
Los caracteres se almacenan en 16 bits
Cuando ve que 256*2**20
caracteres están en una cadena, eso no significa que se hayan asignado 256 megabytes de memoria. JavaScript almacena cada carácter en dos bytes (ya que es utf16 codificado por la especificación).
Una palabra sobre cuerdas
Los navegadores de hoy (incluso IE) almacenan cadenas de una manera avanzada, la mayoría de las veces usando una estructura de datos de cuerdas .
- Las cuerdas no necesitan una región de memoria coherente para ser asignada
- Incluso puede deduplicar subcadenas, eso significa que
s+s
no necesariamente usa el doble de la memoria comos
- La concatenación es muy rápida
- El acceso al elemento es un poco más lento
Al examinar algunas ejecuciones en IE y Chrome, diría que ambas utilizan alguna evaluación diferida para las cadenas, y tratarán de expandirlas ocasionalmente. Después de ejecutar el siguiente fragmento, ninguno de los navegadores utilizó más memoria que antes. Pero si traté de manipular la window.LONGEST_STRING
almacenada.LONGEST_STRING en la consola, IE arrojó un error de falta de memoria, y Chrome se congeló por un corto tiempo, y consumió mucha memoria (> 2 GB).
ps: en mi laptop IE11 tenía un tamaño de cadena máximo de 4 GB, Chrome tenía 512 MB
Comportamiento del navegador
IE11
Chrome47
Un algoritmo más rápido para determinar el tamaño máximo de la cadena
var real_console_log = console.log;
console.log = function(x) {
real_console_log.apply(console, arguments);
var d = document,b=d.body,p=d.createElement(''pre'');
p.style.margin = "0";
p.appendChild(d.createTextNode(''''+x));
b.appendChild(p);
window.scrollTo(0, b.scrollHeight);
};
function alloc(x) {
if (x < 1) return '''';
var halfi = Math.floor(x/2);
var half = alloc(halfi);
return 2*halfi < x ? half + half + ''a'' : half + half;
}
function test(x) {
try {
return alloc(x);
} catch (e) {
return null;
}
}
function binsearch(predicateGreaterThan, min, max) {
while (max > min) {
var mid = Math.floor((max + min) / 2);
var val = predicateGreaterThan(mid);
if (val) {
min = mid + 1;
} else {
max = mid;
}
}
return max;
}
var maxStrLen = binsearch(test, 10, Math.pow(2, 52)) - 1;
console.log(''Max string length is:'');
console.log(maxStrLen + '' characters'');
console.log(2*maxStrLen + '' bytes'');
console.log(2*maxStrLen/1024/1024 + '' megabytes'');
console.log('''');
console.log(''Store longest string'');
window.LONGEST_STRING = alloc(maxStrLen);
console.log(''Try to read first char'');
console.log(window.LONGEST_STRING.charAt(0));
console.log(''Try to read last char'');
console.log(window.LONGEST_STRING.charAt(maxStrLen - 1));
console.log(''Try to read length'');
console.log(window.LONGEST_STRING.length);
Las implementaciones internas pueden usar UCS2 o UTF16. Como @hege_hegedus sugirió, al menos Firefox usa la estructura de Rope ( https://dxr.mozilla.org/mozilla-central/search?q=%2Btype-ref%3ARopeBuilder ). Los códigos me dan los resultados a continuación:
VERSIÓN CROMADA 39.0.2171.95 VERSIÓN DEL SO Linux: 3.13.0-43-generic
Firefox 34.0
Salida de Chrome (desde el código @@ hege_hegedus): La longitud máxima de la cadena es: 268435440 caracteres 536870880 bytes 511.9999694824219 megabytes Almacena la cadena más larga Intenta leer primero la letra a Trata de leer la última letra a. Intenta leer la longitud 268435440
Salida de Firefox (desde el código OP): "La longitud máxima de la cadena es 268435455"
Archivado en http://gpupowered.org/string_js.txt
Un informe de error para el rastreador de cromo tiene este comentario:
... When allocation fails, we create a
Failure pointer encoding the amount requested, as well as some tag and
type bits. This puts a limit on the maximally possible allocation
request in 32-bit versions of 2^27-1. The maximal flat string length is
~2^28 (512MB space), and the maximal string length is 2^29-1...
Tenga en cuenta que esto es a partir de 2009, así que me imagino que esto todavía tiene consecuencias en las versiones actuales de V8 como el enlace anterior es con respecto a una herramienta NodeJS que se ejecuta en los límites de toString()
.