I have successfully compiled stb_dxt
, a DXT texture compressor written in C++, to emscripten and asm.js
. This works wonderfully in Firefox but performance in Chrome is poor. I am therefore attempting to compile the same program to WebAssembly
using the following flags:
emcc -O3 stb_dxt.cpp -o dxt.js -s DISABLE_EXCEPTION_CATCHING=1 -s NO_FILESYSTEM=1 -s EXPORTED_FUNCTIONS="['_rygCompress']" -s WASM=1 -s ALLOW_MEMORY_GROWTH=1
My Javascript glue code, which works perfectly with asm.js
, needs to pass in an image ArrayBuffer
like so:
this.width = input.width;
this.height = input.height;
this.srcSize = input.data.length*input.data.BYTES_PER_ELEMENT;
this.inputPtr = STB.Module._malloc(this.srcSize);
this.outputPtr = STB.Module._malloc(Math.max(8, this.srcSize/8));
this.inputHeap = new Uint8Array(STB.Module.HEAPU8.buffer, this.inputPtr, this.srcSize);
this.outputHeap = new Uint8Array(STB.Module.HEAPU8.buffer, this.outputPtr, Math.max(8, this.srcSize/8));
//set inputHeap to jpeg decoded RGBA data
this.inputHeap.set(input.data);
As you can see I am using _malloc
to allocate the memory for the passed in ArrayBuffer
and also for what will be the resulting output ArrayBuffer
once the program has run and compressed the texture to DXT1.
However, as soon as the first call to _malloc
fires, I am getting an out of bounds memory error:
Uncaught (in promise) RuntimeError: memory access out of bounds
at <WASM UNNAMED> (<WASM>[24]+7062)
at Object.Module._malloc
I assume that I’m doing something wrong, any help would be greatly appreciated.
The code I am trying to compile is available here: https://github.com/nothings/stb/blob/master/stb_dxt.h
My first guess is that wasm startup is async, and perhaps you’re calling into compiled code too early? Building with -s ASSERTIONS=1 -s SAFE_HEAP=1
might find something.
(Otherwise, all those options and that code should work identically on asm.js and wasm, nothing seems wrong there.)
Also worth checking if -s BINARYEN_ASYNC_COMPILATION=0
changes things.
Thanks for the quick response, it’s nearly 1am here. I’ll give your suggestions a try in the morning and let you know how I get on.
@kripken — I’ve tried compiling with the flags you suggested and I now get a series of memory enlargement related errors:
Module.reallocBuffer: Attempted to grow from 16777216 bytes to 134217728 bytes, but got error: RangeError: WebAssembly.Memory.grow(): maximum memory size exceeded
Failed to grow the heap from 16777216 bytes to 134217728 bytes, not enough memory!
failed to set errno from JS
wasm-00010efe-24:3754 Uncaught (in promise) RuntimeError: memory access out of bounds
at <WASM UNNAMED> (<WASM>[24]+7062)
I forgot to mentioned previously, but once I have compiled the program and first run it, I get the following error:
WebAssembly Instantiation: memory import 10 has no maximum limit, expected at most 4294967295
It would appear that WebAssembly has recently changed their instantiation method to require the previously optional «maximum» option to be present.
Therefore, I am manually adding this option into the resulting javascript file following compilation:
Module["wasmMemory"]=new WebAssembly.Memory({"initial":TOTAL_MEMORY/WASM_PAGE_SIZE, "maximum" : 256});
Perhaps this has something to do with it? However, my understanding was this that was only for the WebAssembly instantiation, and was not in any way related to the amount of memory that a compiled program can use, which should be grown internally as it runs.
Perhaps there have been some breaking changes recently?
Interestingly, if I divide the amount of memory I am trying to allocate by WebAssembly’s page size, the call to _malloc
works:
var WASM_PAGE_SIZE = 65536;
this.srcSize = input.data.length * input.data.BYTES_PER_ELEMENT / WASM_PAGE_SIZE ;
this.inputPtr = STB.Module._malloc(this.srcSize);
But then of course, when I then create the Uint8Array()
view and try to set the data, the buffer isn’t large enough.
Why should the _malloc
call fail when I pass in the true length of the input data in bytes? (67108864)
I’ve managed to fix my issue by doing the following:
- Compiling with
-s TOTAL_MEMORY=512MB
- Manually editing the javascript as follows:
Module["wasmMemory"]=new WebAssembly.Memory({"initial":TOTAL_MEMORY/WASM_PAGE_SIZE, "maximum" : TOTAL_MEMORY/WASM_PAGE_SIZE});
Everything then works, but sadly performance is far worse than compiling to asm.js
.
- In Firefox nightly running my program goes from 450ms in asm.js, to around 3,500ms.
- In Chrome Canary, is goes from 1500ms to 3,800ms.
Is there anything I can do to improve this? Or is it simply down to the fact that WebAssembly isn’t optimized to the level of asm.js yet?
The BINARYEN_MEM_MAX
option might help those build issues. Although things should work without it too, so something’s gone wrong, but I don’t remember all the details here to know what offhand — this went through a few revisions.
About perf, that is very surprising. It’s just the wasm flag changed between those? Can you put up links to asm.js and wasm versions, built with --profiling
, so we can reproduce? If it does reproduce, we should file bugs on browsers, although if it makes both of those browsers slower, perhaps it’s our fault in the toolchain somehow.
@kripken — After a few hours of profiling and tweaking I have been able to improve on performance to the point where the WASM version is now significantly faster then the asm.js one, in Chrome. Firefox is still slightly faster when using asm.js however. Regardless, it seems that setting the input buffer in Chrome was causing a huge bottleneck for me but witching to Uint32Array
views over the input ArrayBuffer
made the copy far faster and solved it.
So this is great news, but still, I have to manually edit and include a maximum
property in the javascript that’s output by Emscripten.
It would appear that WebAssembly has recently changed their instantiation method to require the previously optional «maximum» option to be present.
Do you have more info about this? I believe maximum should still be optional?
Do you have more info about this? I believe maximum should still be optional?
The only info I can give you is that without the maximum
option being explicitly stated, compilation fails for me, giving a memory import 10 has no maximum limit
error. The second I provide the option and set it to the same as the already present initial
value, the error goes away and everything works.
This is using the latest incoming build of Emscripten… Sorry I can’t be any more help.
Very strange. We need a full testcase to diagnose this, I think, I’m not sure where things are going wrong.
We’re also experiencing rare errors like this sometimes at Figma, but only in Chrome (not Firefox). I logged a bug with Chrome before I found this issue.
I finally got SAFE_HEAP working. I verified that SAFE_HEAP works by making sure *(char*)0x3FFFFFFF
triggers the heap checks (in both Firefox and Chrome). I then ran Figma with SAFE_HEAP enabled and no heap checks were triggered (in both Firefox and Chrome) but Firefox loaded fine and Chrome threw «memory access out of bounds». Does this mean the bug is in Chrome and not in emscripten? Is there anything else I should try?
I’m pretty sure it’s a Chrome bug at this point, yeah. One last thing I’d try is to build with -s DETERMINISTIC=1
which removes timing and randomness out of the picture. Also can’t hurt to add ASSERTIONS
.
ASSERTIONS was a good idea. It looks like this is the problem:
Module.reallocBuffer: Attempted to grow from 1073741824 bytes to 1342177280 bytes, but got error: RangeError: WebAssembly.Memory.grow(): maximum memory size exceeded
Firefox allows the memory to grow over 1gb while Chrome doesn’t. Figma sometimes needs more than 1gb of memory for large documents. Is the 1gb limit something that emscripten sets? Or is this a limitation of Chrome’s implementation in particular?
I saw your comment above about BINARYEN_MEM_MAX
so I tried -s BINARYEN_MEM_MAX=2147418112
but Chrome still fails to grow to 1342177280.
Interesting. Looks like a chrome bug, emscripten doesn’t set a 1GB limit (and it wouldn’t be browser-specific in any case). Let’s maybe move the discussion back to the chromium bug tracker to make sure they see it.
Another thought here (not relevant to the Chrome side, so not posting in the bug there): in Chrome the allocation failed, so your app should have seen malloc/new return NULL. Does that happen properly for you, or is emscripten messing that up somehow?
(That’s assuming you have ABORTING_MALLOC
turned off, which I think is the case? Otherwise it should have called abort and halted the app.)
The crash is actually in malloc, not in our code. The call to malloc is still executing (i.e. at the top of the call stack) when the crash occurs so it never has the chance to return null. Here’s what the stack trace looks like:
Uncaught RuntimeError: memory access out of bounds
at <WASM UNNAMED> (<WASM>[331 (_malloc)]+4483)
at <WASM UNNAMED> (<WASM>[703 (_malloca)]+138)
at <WASM UNNAMED> (<WASM>[714 (operator new(unsigned int))]+9)
at <WASM UNNAMED> (<WASM>[6072 (Codec::encodePhaseAndPropertyChanges(MultiplayerMessage const&, Fig::Message&))]+772)
at <WASM UNNAMED> (<WASM>[6070 (Codec::toBuffer(MultiplayerMessage const&, MessageFormat))]+1135)
at <WASM UNNAMED> (<WASM>[6069 (MultiplayerMessage::toBuffer(ImageMode, MessageFormat) const)]+197)
...
For what it’s worth, I did verify that we aren’t get any calls to malloc returning NULL before the crash.
I think I’ve figured it out. We #define MALLOC_ALIGNMENT 16
before dlmalloc.cpp. This is supposed to be safe:
MALLOC_ALIGNMENT default: (size_t)(2 * sizeof(void *))
Controls the minimum alignment for malloc'ed chunks. It must be a
power of two and at least 8, even on machines for which smaller
alignments would suffice. It may be defined as larger than this
though. Note however that code and data structures are optimized for
the case of 8-byte alignment.
Calling malloc crashes in Chrome if we #define MALLOC_ALIGNMENT 16
but doesn’t crash if we #define MALLOC_ALIGNMENT 8
(the default). Any idea why this might be?
Scratch that, never mind. That just lets us load the app in barely under 1gb. We still have the same problem if I make the document slightly bigger.
Yeah, that crashing in malloc is definitely a sign of a problem in emscripten. I debugged it and found the issues, fixes and details in #5289.
Should be fixed by that merged PR.
I’m also experiencing this error when my program runs for a few minutes in Chrome
Uncaught RuntimeError: memory access out of bounds
at wasm-function[79]:46
at wasm-function[401]:379
at wasm-function[992]:1112
at wasm-function[338]:533
at wasm-function[1253]:704
at wasm-function[748]:707
at wasm-function[1378]:245
at wasm-function[1348]:205
at wasm-function[1356]:9
@Y0QIN — that might be a different issue, as I think the one here was fixed. To debug it, I’d start with building with -g
so that stack trace is readable, and then hopefully what’s going wrong can be figured out. If not, if you can share a testcase we can debug that here.
surikov
added a commit
to surikov/riffshare
that referenced
this issue
Nov 19, 2018
Hi, I am trying to get my Unity LEGO microgame uploaded to play.unity.com.
I can build to WebGL and it uploads the game, but when I try to play it in my browser (chrome) it gives the following error:
‘An error occured running the Unity content on this page. See your browser Javascript console for more info. the error was: Uncaught RuntimeError: memory access out of bounds.’
You can try it here for yourself: https://play.unity.com/mg/lego/web-0osz7
I thought maybe the game was too heavy so I tried stripping the whole game down until there was barely anything left, but it still gives the same error when playing the uploaded build.
Edit: stripping down the game seems to work, I think I will have to rebuild and reupload untill I hit the maximum…
The chrome console shows these errors:
Uncaught RuntimeError: memory access out of bounds
at <anonymous>:wasm-function[39464]:0xe48aa0
at <anonymous>:wasm-function[39463]:0xe48a33
at <anonymous>:wasm-function[39462]:0xe489c9
at <anonymous>:wasm-function[49594]:0x10a110c
at <anonymous>:wasm-function[49601]:0x10a1f8f
at <anonymous>:wasm-function[49599]:0x10a1a95
at <anonymous>:wasm-function[49598]:0x10a181f
at <anonymous>:wasm-function[25339]:0xb97bac
at dynCall_iiiii (<anonymous>:wasm-function[52471]:0x111f01b)
at Object.dynCall_iiiii (blob:https://play.unity3dusercontent.com/08f085a7-7fd5-42f4-a591-d067454a8d6a:8:463265)
at invoke_iiiii (blob:https://play.unity3dusercontent.com/08f085a7-7fd5-42f4-a591-d067454a8d6a:8:331727)
at <anonymous>:wasm-function[50596]:0x10c8f11
at <anonymous>:wasm-function[50050]:0x10b0ed8
at <anonymous>:wasm-function[4469]:0x1b7b8d
at <anonymous>:wasm-function[4467]:0x1b7865
at <anonymous>:wasm-function[8137]:0x2f5ff6
at <anonymous>:wasm-function[8134]:0x2f4e18
at <anonymous>:wasm-function[10603]:0x40081f
at <anonymous>:wasm-function[8402]:0x3162cc
at <anonymous>:wasm-function[10989]:0x42cea0
at <anonymous>:wasm-function[10703]:0x40a3f0
at <anonymous>:wasm-function[10703]:0x40a405
at <anonymous>:wasm-function[10698]:0x409f0f
at <anonymous>:wasm-function[10691]:0x408112
at dynCall_v (<anonymous>:wasm-function[52485]:0x111f24d)
at Object.dynCall_v (blob:https://play.unity3dusercontent.com/08f085a7-7fd5-42f4-a591-d067454a8d6a:8:471234)
at browserIterationFunc (blob:https://play.unity3dusercontent.com/08f085a7-7fd5-42f4-a591-d067454a8d6a:8:166325)
at Object.runIter (blob:https://play.unity3dusercontent.com/08f085a7-7fd5-42f4-a591-d067454a8d6a:8:169386)
at Browser_mainLoop_runner (blob:https://play.unity3dusercontent.com/08f085a7-7fd5-42f4-a591-d067454a8d6a:8:167848)
Многие пользователи ПК во время работы с какой-либо программой могут столкнуться с «вылетом» указанной программы, и появившимся сообщением «Out of memory». Возникшая проблема может иметь множество причин, начиная от банального недостатка памяти на пользовательском ПК, и заканчивая некорректной работой с памятью какой-либо программы.
- Причины появления дисфункции
- Как исправить ошибку «Out of memory»
- Заключение
Причины появления дисфункции
Сообщение «Out of memory» (в переводе дословно «вне памяти», или «недостаточно памяти») обычно возникает при недостатке памяти на пользовательском компьютере. В частности же, в появлении данной ошибки «виновен» следующий набор факторов:
- Недостаток памяти RAM на вашем ПК (рабочей памяти, планки которой установлены на материнской плате вашего компьютера). Если на вашем компьютере установлен всего 1 гигабайт памяти, вы будете встречаться с описываемой ошибкой довольно часто. Нормальным же ныне считается наличие на компьютере 4 гигабайт памяти и выше;
- Недостаток места на жёстком диске.
Когда вашему компьютеру не хватает физической R.A.M. памяти, он заимствует часть места на жёстком диске, и создаёт так называемую «виртуальную память». Система временно хранит в такой виртуальной памяти ту часть данных, которая не помещается в памяти обычной. Такие данные обычно хранятся в файле «pagefile.sys», размер которого может увеличиваться или уменьшаться в зависимости от специфики работы вашей ОС. Если на диске будет недостаточно места, файл «pagefile.sys» не сможет расти, и пользователь получит рассматриваемую ошибку.
- При одновременном запуске на ПК большого количества программ, каждая из которых бронирует часть памяти ПК под свои задачи;
- При запуск большого количества вкладок браузера. Веб-навигаторы уровня «Firefox» или «Google Chrome» способны занимать от 500 мегабайт до 1 гигабайта памяти под свой функционал, при этом число открытых вкладок и соответствующей обслуживающей памяти может быть ограничено системой. Специалисты Майрософт называют такую проблему «the desktop heap limitation» — «ограничение кучи рабочего стола»);
- Некорректная работа с памятью ряда программ (наиболее часто это игровые программы);
- Не оптимальный размер файла подкачки, с которым работает система.
Как исправить ошибку «Out of memory»
Для решения указанной проблемы рекомендую сделать следующее:
- Перезагрузите ваш ПК, и запустите требуемую программу вновь. Возможно, что проблема имеет случайный характер, и более повторяться не будет;
- Перед запуском нужной программы закройте другие ненужные программы (браузер, музыкальный или видео плеер, текстовый или графический редактор, мессенджер и так далее);
- Если проблема возникает во время серфинга в сети, закройте всё множество вкладок вашего браузера (при наличии), оставив лишь одну или две.
Альтернативным вариантом решения проблемы является установка соответствующего фикса от Майкрософт. Или использование расширений или дополнений для браузера уровня «The Great Suspender» для «Google Chrome», хорошо работающего с ненужными вкладками браузера.
- Добавьте оперативной памяти на ваш ПК. Если у вас на компьютере установлено 1-2 гигабайта памяти, будет оптимальным довести её объём до 4 гигабайт (а для 64-битных Виндовс 7, 8 и 10 версии рекомендую 8 и более гигабайт);
- Убедитесь, что на вашем жёстком диске (или SSD) достаточно свободного места. При необходимости, освободите диск от ненужных файлов;
- Используйте инструмент командной строки BCDEdit для изменения параметров загрузки системы. Если у вас на ПК установлена Виндовс 7 и более, запустите командную строку от имени администратора на Виндовс 7 и Виндовс 10, и в ней наберите:
bcdedit/set IncreaseUserVa 3072
И нажмите на ввод, и перезагрузите ваш ПК. Функционал данной команды позволяет выделить пользовательским приложениям 3 гигабайта оперативной памяти для работы. В некоторых системах этого может быть слишком много, потому если после ввода данной команды система начала чаще сбоить, то введите в командной строке от имени администратора:
bcdedit /set IncreaseUserVa 2560 — что позволит задействовать 2,5 гигабайта вместо ранее забронированных 3.
Если ситуацию этим исправить не удалось, верните настройки на состояние по умолчанию:
bcdedit /deletevalue IncreaseUserVa
- Увеличьте объём файла подкачки. Нажмите кнопку «Пуск», в строке поиска введите sysdm.cpl и нажмите ввод. В открывшемся окне настроек системы выберите «Дополнительно» — «Быстродействие» — «Параметры» — «Дополнительно» — «Виртуальная память» — «Изменить». Снимите галочку с опции автоматического размера, поставьте галочку на «Указать размер», и поставьте исходный размер в 8192, и максимальный в 8192. Затем выберите «Задать»;
Установите нужный размер файла подкачки
- Если ошибка возникает при использовании игровой программы, перейдите в её графические настройки, и выберите их минимальные значения;
- Произведите правильную настройку «Java». Для решения проблем с игровой программой «Майнкрафт» перейдите в Панель управления Виндовс, найдите там «Java» и запустите данную среду исполнения. Нажмите на кнопку «View», затем дважды кликните на «Runtime Parametres». Введите туда –Xms256m – Xmx3072m (или больше). Xms – это минимальное выделение ОЗУ, Xmx – максимальное. Значение Xmx рекомендуют устанавливать на процентов 70-80% от общего объёма ОЗУ. Примените изменения, и перезагрузите ваш ПК.
Заключение
Ошибка «Out of memory» может иметь множество причин, связанных как с физическим недостатком памяти на ПК, так и другими детерминантами, изложенными мной выше. Для решения проблемы советую закрыть ненужные программы (вкладки браузера) на вашем компьютере (тем самым разгрузив его память), а самым эффективным инструментом является установка дополнительной планки памяти на ПК, что в большинстве случаев поможет избавиться от ошибки на вашем компьютере.