Was bedeutet es, C-Code in einem Browser auszuführen? WebAssembly war eine der Technologien, an denen ich interessiert war, weil ich mich in meinem vorherigen Job mit C befasst hatte. In diesem Artikel habe ich zusätzlich zu HelloWorld die Ergebnisse eines kleinen Experiments zusammengefasst.
** Installieren Sie Emscripten (Compiler) **
#Die diesmal installierte Version
$ emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 1.39.16
clang version 11.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 3774bcf9f84520a8c35bf765d9a528040d68a14b)
Target: x86_64-apple-darwin19.5.0
Thread model: posix
shared:INFO: (Emscripten: Running sanity checks)
↓
** Erstelle hallo.c **
hello.c
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n");
return 0;
}
↓
kompilieren
#Vor dem Zusammenstellen
$ ls
hello.c
#kompilieren
$ emcc hello.c -s WASM=1 -o hello.html
# wasm, js,HTML wurde generiert
$ ls -l
total 496
-rw-r--r-- 1 arene staff 95 5 19 21:55 hello.c
-rw-r--r-- 1 arene staff 102675 5 21 21:50 hello.html
-rw-r--r-- 1 arene staff 115917 5 21 21:50 hello.js #2600 Zeilen(!)
-rw-r--r-- 1 arene staff 21727 5 21 21:50 hello.wasm
Die nach der Kompilierung generierte js-Datei hat satte 2600 Zeilen. Sie können sehen, dass es eine schwierige Technologie ist. Natürlich konnte Code, der nicht als C kompiliert werden konnte, auch nicht in WASM kompiliert werden.
↓ ** Aktivieren Sie die experimentelle Web Assembly auf Chrome: // flags / **
↓ ** Richten Sie einen Webserver auf Ihrem lokalen PC ein **
#Emscripten bietet sogar einen einfachen Webserver
$ emrun --no_browser --port 8080 .
Web server root directory: /Users/arene/temporary/wasm
Now listening at http://0.0.0.0:8080/
↓ ** Öffnen Sie hello.html in Ihrem Browser **
Der Code, der beim Kompilieren von HelloWorld automatisch generiert wurde, sah folgendermaßen aus. (Da es nicht richtig analysiert wurde und es viele davon gibt, werden nur die Teile extrahiert, an denen die Atmosphäre leicht zu erfassen ist.)
hello.html
<!--Lassen Sie Logos, terminalähnliche Bildschirme und andere unnötige Elemente weg-->
<script async type="text/javascript" src="hello.js"></script>
hello.js
//Der tatsächliche Code ist 2600 Zeilen
//Um mir einen Überblick zu verschaffen, habe ich es so extrahiert
//Die Reihenfolge der Funktionsdefinition wurde ebenfalls geändert, damit sie von Anfang an gelesen werden kann.(Tatsächlich`run();`Ist am Ende der Datei)
var wasmBinaryFile = 'hello.wasm';
if (!isDataURI(wasmBinaryFile)) {
wasmBinaryFile = locateFile(wasmBinaryFile);
}
run(); //Dieser Typ am Ende der Datei ist der Ausgangspunkt für alles
function run(args) {
//Sehr verschiedene Auslassungen
callMain(args)
}
function callMain(args) {
//Sehr verschiedene Auslassungen
var entryFunction = Module['_main']; // Module['xxx']Es gibt viele Dinge, einschließlich der Hauptfunktion.
var ret = entryFunction(argc, argv);
exit(ret, true);
}
//Modul C funktioniert so["asm"]Verbunden mit
var asm = createWasm();
Module["asm"] = asm;
var _main = Module["_main"] = function() {
assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
return Module["asm"]["main"].apply(null, arguments)
};
var _malloc = Module["_malloc"] = function() {
assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. wait for main() to be called)');
assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
return Module["asm"]["malloc"].apply(null, arguments)
};
var _free = Module["_free"] = function() {
assert(runtimeInitialized, 'you need to wait for the runtime to be ready (e.g. waMBit for main() to be called)');
assert(!runtimeExited, 'the runtime was exited (use NO_EXIT_RUNTIME to keep it alive after main() exits)');
return Module["asm"]["free"].apply(null, arguments)
};
** Bereiten Sie Code vor, der für jede Sekunde 100 KB Speicher verliert **
memoryLeak.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void memoryLeak(void) {
int shouldLoop = 1;
int loopCount = 0;
while(shouldLoop) {
loopCount++;
if (loopCount > 10) {
shouldLoop = 0;
}
char* p = malloc(1024 * 100); //Speicher dynamisch zuordnen. Da es nicht freigegeben wird, tritt für jede Schleife ein Speicherverlust auf.
printf("memory leak: leak 100KB!\n");
usleep(1000 * 1000); // 1000msec
}
return;
}
int main(int argc, char *argv[]) {
printf("memory leak: start\n");
memoryLeak();
printf("memory leak: end\n");
return 0;
}
↓ ** Führen Sie es nach dem Kompilieren in einem Browser aus und messen Sie die Leistung mit devtool **
JS Heap hat nicht zugenommen und auf der Vorderseite wurde kein Speicherverlust festgestellt. ...Was meinst du? (Da in Liste der Vorschläge ein GC enthalten ist, scheint der GC nicht funktioniert zu haben.)
Ich dachte, dass der Grund, warum ich den Speicherverlust im vorherigen Abschnitt nicht bestätigen konnte, darin bestand, dass die Leckbreite klein und schwer zu verstehen war, also habe ich die Leckbreite erweitert. Ich habe es in einen Code umgeschrieben, der alle 100 ms 1 MB ausläuft, was insgesamt 100 MB entspricht, und als ich es auf die gleiche Weise überprüft habe, ist der folgende Fehler aufgetreten.
Es ist unklar, welche Schicht begrenzt ist, Browser, WASM, Betriebssystem, aber es scheint, dass der verfügbare Speicher begrenzt ist. (Natürlich, natürlich)
console.log
Cannot enlarge memory arrays to size 17534976 bytes (OOM). Either (1) compile with -s INITIAL_MEMORY=X with X higher than the current value 16777216, (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0
memoryLeak.html:1246 Cannot enlarge memory arrays to size 17534976 bytes (OOM). Either (1) compile with -s INITIAL_MEMORY=X with X higher than the current value 16777216, (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0
memoryLeak.html:1246 exception thrown: RuntimeError: abort(Cannot enlarge memory arrays to size 17534976 bytes (OOM). Either (1) compile with -s INITIAL_MEMORY=X with X higher than the current value 16777216, (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ) at Error
at jsStackTrace (http://0.0.0.0:8080/memoryLeak.js:1978:17)
at stackTrace (http://0.0.0.0:8080/memoryLeak.js:1995:16)
at abort (http://0.0.0.0:8080/memoryLeak.js:1735:44)
at abortOnCannotGrowMemory (http://0.0.0.0:8080/memoryLeak.js:2018:7)
at _emscripten_resize_heap (http://0.0.0.0:8080/memoryLeak.js:2021:7)
at wasm-function[13]:0x237a
at wasm-function[11]:0xd36
at wasm-function[8]:0x337
at wasm-function[9]:0x407
at Module._main (http://0.0.0.0:8080/memoryLeak.js:2212:32),RuntimeError: abort(Cannot enlarge memory arrays to size 17534976 bytes (OOM). Either (1) compile with -s INITIAL_MEMORY=X with X higher than the current value 16777216, (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ) at Error
at jsStackTrace (http://0.0.0.0:8080/memoryLeak.js:1978:17)
at stackTrace (http://0.0.0.0:8080/memoryLeak.js:1995:16)
at abort (http://0.0.0.0:8080/memoryLeak.js:1735:44)
at abortOnCannotGrowMemory (http://0.0.0.0:8080/memoryLeak.js:2018:7)
at _emscripten_resize_heap (http://0.0.0.0:8080/memoryLeak.js:2021:7)
at wasm-function[13]:0x237a
at wasm-function[11]:0xd36
at wasm-function[8]:0x337
at wasm-function[9]:0x407
at Module._main (http://0.0.0.0:8080/memoryLeak.js:2212:32)
at abort (http://0.0.0.0:8080/memoryLeak.js:1741:9)
at abortOnCannotGrowMemory (http://0.0.0.0:8080/memoryLeak.js:2018:7)
at _emscripten_resize_heap (http://0.0.0.0:8080/memoryLeak.js:2021:7)
at wasm-function[13]:0x237a
at wasm-function[11]:0xd36
at wasm-function[8]:0x337
at wasm-function[9]:0x407
at Module._main (http://0.0.0.0:8080/memoryLeak.js:2212:32)
at callMain (http://0.0.0.0:8080/memoryLeak.js:2500:15)
at doRun (http://0.0.0.0:8080/memoryLeak.js:2562:23)
memoryLeak.js:1741 Uncaught RuntimeError: abort(Cannot enlarge memory arrays to size 17534976 bytes (OOM). Either (1) compile with -s INITIAL_MEMORY=X with X higher than the current value 16777216, (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0 ) at Error
at jsStackTrace (http://0.0.0.0:8080/memoryLeak.js:1978:17)
at stackTrace (http://0.0.0.0:8080/memoryLeak.js:1995:16)
at abort (http://0.0.0.0:8080/memoryLeak.js:1735:44)
at abortOnCannotGrowMemory (http://0.0.0.0:8080/memoryLeak.js:2018:7)
at _emscripten_resize_heap (http://0.0.0.0:8080/memoryLeak.js:2021:7)
at wasm-function[13]:0x237a
at wasm-function[11]:0xd36
at wasm-function[8]:0x337
at wasm-function[9]:0x407
at Module._main (http://0.0.0.0:8080/memoryLeak.js:2212:32)
at abort (http://0.0.0.0:8080/memoryLeak.js:1741:9)
at abortOnCannotGrowMemory (http://0.0.0.0:8080/memoryLeak.js:2018:7)
at _emscripten_resize_heap (http://0.0.0.0:8080/memoryLeak.js:2021:7)
at wasm-function[13]:0x237a
at wasm-function[11]:0xd36
at wasm-function[8]:0x337
at wasm-function[9]:0x407
at Module._main (http://0.0.0.0:8080/memoryLeak.js:2212:32)
at callMain (http://0.0.0.0:8080/memoryLeak.js:2500:15)
at doRun (http://0.0.0.0:8080/memoryLeak.js:2562:23)
Schließlich habe ich versucht, den Code auszuführen, der den Laufzeitfehler verursacht hat. Das Ergebnis war natürlich ein Laufzeitfehler im Browser. Der Code nach der Zeile, die den Laufzeitfehler verursacht hat, wurde jedoch ebenfalls ausgeführt. (Wenn Sie es normal als C ausführen, wird es an der Fehlerstelle gelöscht, sodass es geringfügig anders ist.
segfault.c
#include <stdio.h>
int main(void) {
int i;
char str[4];
char* p;
printf("Before Segmentation Fault\n");
for(i = 0; i < 16; i++) {
str[i] = 'a';
*p = str[i];
}
printf("After Segmentation Fault\n");
return 0;
}
#Beim normalen Kompilieren und Ausführen als C-Sprache schlägt dies im Fehlerteil fehl
$ gcc segfault.c
$ ./a.out
Before Segmentation Fault
[1] 22777 segmentation fault ./a.out
Bei der Ausführung über den Browser wird die Verarbeitung auch nach dem Fehlerteil fortgesetzt
Fehler bei der Konsolenanmeldung
console.log
segfault.html:1246 Runtime error: The application has corrupted its heap memory area (address zero)!
segfault.js:1741 Uncaught RuntimeError: abort(Runtime error: The application has corrupted its heap memory area (address zero)!) at Error
at jsStackTrace (http://0.0.0.0:8080/segfault.js:1978:17)
at stackTrace (http://0.0.0.0:8080/segfault.js:1995:16)
at abort (http://0.0.0.0:8080/segfault.js:1735:44)
at checkStackCookie (http://0.0.0.0:8080/segfault.js:1446:46)
at postRun (http://0.0.0.0:8080/segfault.js:1538:3)
at doRun (http://0.0.0.0:8080/segfault.js:2545:5)
at http://0.0.0.0:8080/segfault.js:2554:7
at abort (http://0.0.0.0:8080/segfault.js:1741:9)
at checkStackCookie (http://0.0.0.0:8080/segfault.js:1446:46)
at postRun (http://0.0.0.0:8080/segfault.js:1538:3)
at doRun (http://0.0.0.0:8080/segfault.js:2545:5)
at http://0.0.0.0:8080/segfault.js:2554:7
Irgendwann wird alles im Browser erledigt und ich habe einen Traum.
Recommended Posts