브라우저에서 JavaScript가 처리 할 수있는 개체 크기의 한계에 도달 했습니까?
다음 <script>
과 같이 HTML의 태그에 큰 배열을 포함하고 있습니다 (놀랍지 않습니다).
<script>
var largeArray = [/* lots of stuff in here */];
</script>
이 특정 예에서 배열에는 210,000 개의 요소가 있습니다. 이것은 이론적 최대치 인 2 31 x 4 자릿수 보다 훨씬 낮습니다 . 여기 재미있는 부분이 있습니다. 배열의 JS 소스를 파일에 저장하면 해당 파일은 44 메가 바이트 (정확히 46,573,399 바이트)가됩니다.
직접보고 싶다면 GitHub에서 다운로드 할 수 있습니다 . (그 안에있는 모든 데이터가 통조림으로되어 있으므로 많은 부분이 반복됩니다. 프로덕션에서는 그렇지 않습니다.)
이제 저는 그렇게 많은 데이터를 제공 하는 것에 대해 정말로 걱정하지 않습니다 . 내 서버는 응답을 gzip하므로 유선을 통해 데이터를 가져 오는 데 그렇게 오래 걸리지 않습니다. 그러나 페이지가로드되면 브라우저 가 중단 되는 매우 불쾌한 경향이 있습니다. 나는 IE에서 전혀 테스트하지 않고 있습니다 (이것은 내부 도구입니다). 내 주요 대상은 Chrome 8 및 Firefox 3.6입니다.
Firefox에서는 콘솔에서 상당히 유용한 오류를 볼 수 있습니다.
Error: script stack space quota is exhausted
Chrome에서는 단순히 슬픈 탭 페이지가 표시됩니다.
벌써 추격전
- 이가 정말 핸들 현대, "고성능"브라우저에 대한 너무 많은 데이터가?
- 이 정도의 데이터를 정상적으로 처리하기 위해 제가 할 수있는 일이 있습니까?
덧붙여서, Chrome에서이 기능을 켜고 끌 수있었습니다 (읽기 : 탭 충돌 안 함). 나는 Chrome이 적어도 더 힘든 것으로 만들어 졌다고 생각했지만 분명히 내가 틀렸다 ...
편집 1
@Crayon : 이 많은 데이터를 한 번에 브라우저에 버리고 싶은 이유 를 정당화 하려고 하지 않았습니다 . 짧은 버전 :이 문제를 해결하거나 (분명히 쉽지는 않은) 문제를 해결해야합니다. 아니면 다른 많은 문제를 해결해야합니다. 지금은 더 간단한 접근 방식을 선택하고 있습니다.
@various : 지금은 배열의 요소 수를 실제로 줄이는 방법을 특별히 찾고 있지 않습니다. Ajax 페이징 또는 What-have-you를 구현할 수 있다는 것을 알고 있지만 다른 측면에서 나에게 고유 한 문제가 발생합니다.
@Phrogz : 각 요소는 다음과 같습니다.
{dateTime:new Date(1296176400000),
terminalId:'terminal999',
'General___BuildVersion':'10.05a_V110119_Beta',
'SSM___ExtId':26680,
'MD_CDMA_NETLOADER_NO_BCAST___Valid':'false',
'MD_CDMA_NETLOADER_NO_BCAST___PngAttempt':0}
@Will :하지만 저는 4 코어 프로세서, 6 기가 바이트 RAM, 0.5 테라 바이트 이상의 디스크 공간이있는 컴퓨터를 가지고 있습니다. 브라우저에이 작업을 빠르게 요청하지도 않습니다. 전혀 작동 하지 않습니다! ☹
편집 2
임무 완수!
Juan 과 Guffa의 즉각적인 제안 으로이 작업을 수행 할 수있었습니다! 문제는 소스 코드 를 구문 분석 하는 데 있었으며 실제로 메모리에서 작동하지 않는 것처럼 보입니다 .
Juan의 답변에 대한 의견 수렁을 요약하자면 큰 배열을 일련의 작은 배열로 분할 한 다음 배열 Array#concat()
해야했지만 충분하지 않았습니다. 나는 또한 그것들을 별도의 var
진술 에 넣어야했다 . 이렇게 :
var arr0 = [...];
var arr1 = [...];
var arr2 = [...];
/* ... */
var bigArray = arr0.concat(arr1, arr2, ...);
이 문제를 해결하는 데 기여한 모든 사람에게 감사합니다. 첫 번째 라운드가 나에게 있습니다!
* 명백한 것 외에 : 브라우저에 더 적은 데이터 전송
제가 시도해 볼 것은 다음과 같습니다. 44MB 파일이라고하셨습니다. 분명히 44MB 이상의 메모리가 필요합니다. 44MB 이상의 RAM, 아마도 반 기가를 차지한다고 생각합니다. 브라우저가 충돌하지 않고 브라우저가 사용하는 메모리 양을 볼 때까지 데이터를 줄일 수 있습니까?
서버에서만 실행되는 앱도 44MB 파일을 읽지 않고 메모리에 보관하는 것이 좋습니다. 모든 것을 말 했으니 브라우저가 그것을 처리 할 수 있어야한다고 생각하므로 몇 가지 테스트를 실행하겠습니다.
(Windows 7, 4GB 메모리 사용)
첫 번째 테스트 어레이를 반으로 자르고 문제가 없었고 80MB를 사용하고 충돌이 없음
Second Test I split the array into two separate arrays, but still contains all the data, uses 160Mb, no crash
Third Test Since Firefox said it ran out of stack, the problem is probably that it can't parse the array at once. I created two separate arrays, arr1, arr2 then did arr3 = arr1.concat(arr2); It ran fine and uses only slightly more memory, around 165MB.
Fourth Test I am creating 7 of those arrays (22MB each) and concatting them to test browser limits. It takes about 10 seconds for the page to finish loading. Memory goes up to 1.3GB, then it goes back down to 500MB. So yeah chrome can handle it. It just can't parse it all at once because it uses some kind of recursion as can be noticed by the console's error message.
Answer Create separate arrays (less than 20MB each) and then concat them. Each array should be on its own var statement, instead of doing multiple declarations with a single var.
I would still consider fetching only the necessary part, it may make the browser sluggish. however, if it's an internal task, this should be fine.
Last point: You're not at maximum memory levels, just max parsing levels.
Yes, it's too much to ask of a browser.
That amount of data would be managable if it already was data, but it isn't data yet. Consider that the browser has to parse that huge block of source code while checking that the syntax adds up for it all. Once parsed into valid code, the code has to run to produce the actual array.
So, all of the data will exist in (at least) two or three versions at once, each with a certain amount of overhead. As the array literal is a single statement, each step will have to include all of the data.
Dividing the data into several smaller arrays would possibly make it easier on the browser.
Try retrieving the data with Ajax as an JSON page. I don't know the exact size but I've been able to pull large amounts of data into Google Chrome that way.
Do you really need all the data? can't you stream just the data currently needed using AJAX? Similar to Google Maps - you can't fit all the map data into browser's memory, they display just the part you are currently seeing.
Remember that 40 megs of hard data can be inflated to much more in browser's internal representation. For example the JS interpreter may use hashtable to implement the array, which would add additional memory overhead. Also, I expect that the browsers stores both source code and the JS memory, that alone doubles the amount of data.
JS is designed to provide client-side UI interaction, not handle loads of data.
EDIT:
Btw, do you really think users will like downloading 40 megabytes worth of code? There are still many users with less than broadband internet access. And execution of the script will be suspended until all the data is downloaded.
EDIT2:
I had a look at the data. That array will definitely be represented as hashtable. Also many of the items are objects, which will require reference tracking...that is additional memory.
I guess the performance would be better if it was simple vector of primitive data.
EDIT3: The data could certainly be simplified. The bulk of it are repeating strings, which could be encoded in some way as integers or something. Also, my Opera is having trouble just displaying the text, let alone interpreting it.
EDIT4: Forget the DateTime objects! Use unix era timestamps or strings, but not objects!
EDIT5: Your processor doesn't matter because JS is single-threaded. And your RAM doesn't matter either, most browsers are 32bit, so they can't use much of that memory.
EDIT6: Try changing the array indices to sequential integers (0, 1, 2, 3...). That might make the browser use more efficient array data structure. You can use constants to access the array items efficiently. This is going to cut down the array size by huge chunk.
Use lazy loading. Have pointers to the data and get it when the user asks.
This technique is used in various places to manage millions of records of data.
[Edit]
I found what I was looking for. Virtual scrolling in the jqgrid. That's 500k records being lazy loaded.
I would try having it as one big string with separator between each "item" then use split
, something like:
var largeString = "item1,item2,.......";
var largeArray = largeString.split(",");
Hopefully string won't exhaust the stack so fast.
편집 : 그것을 테스트하기 위해 200,000 개의 간단한 항목 (각 항목 하나의 번호)으로 더미 배열을 만들고 Chrome은 즉시로드했습니다. 2,000,000 개 항목? 몇 초이지만 충돌은 없습니다. 6,000,000 개의 항목 배열 (50MB 파일)로 인해 Chrome이 약 10 초 동안로드되었지만 두 가지 방식으로 충돌이 발생하지 않았습니다.
그래서 이것은 문제가 배열 자체가 아니라 내용 이라고 믿게합니다 . 내용을 간단한 항목으로 최적화 한 다음 "즉시"파싱하면 작동합니다.
'Program Tip' 카테고리의 다른 글
새로운 기능이없는 C ++ 개체 (0) | 2020.11.24 |
---|---|
기능을 삭제하지 않고 specflow (Gherkin)에서 기능을 비활성화하려면 어떻게합니까? (0) | 2020.11.24 |
Android MVVM 디자인 패턴 예제 (0) | 2020.11.24 |
C ++의 man 페이지는 어디에 있습니까? (0) | 2020.11.24 |
Python-파일 및 폴더 이동 및 덮어 쓰기 (0) | 2020.11.24 |