Upgrade to Pro — share decks privately, control downloads, hide ads and more …

オブジェクトライフサイクルとメモリ管理を学ぼう / OOC 2020

オブジェクトライフサイクルとメモリ管理を学ぼう / OOC 2020

Akira Morikawa

February 15, 2020
Tweet

More Decks by Akira Morikawa

Other Decks in Technology

Transcript

  1. #ooc_2020 #ooc_b 11 CPU Register Processor RAM BUS ( Front

    Side Bus ) ( Cache ) LOAD STORE Page CPU/RAM の動作 • CPU はレジスタに内部データを保管 ◦ x64 の汎用レジスタは 64bit × 16 ◦ 最近の CPU は複数段キャッシュ • CPU/BUS/RAM で動作周波数が異なる ◦ CPU 外との通信は相対的に遅い ◦ データ読書単位=レジスタサイズ
  2. #ooc_2020 #ooc_b 13 アドレス変換 Address Translation new Object (); 論理アドレス

    物理アドレス ページテーブル ※リニアアドレス省略
  3. #ooc_2020 #ooc_b ( 最大メモリ 256 TB ) 14 アドレス変換 Address

    Translation x64 ページテーブル PML4 ( Page Map Level 4 Table ) PDPT ( Page Directory Pointer Table ) PDE ( Page Directory Entry ) PTE ( Page Table Entry ) 4 KB 2 MB 1 GB 48 bit addressing
  4. #ooc_2020 #ooc_b Page ( 4 KB ) 15 アドレス変換 Address

    Translation PML4 PDPT PDE PTE 64bit ( 48bit ) Virtual Address 47 0 11 20 29 38 CR3 Register
  5. #ooc_2020 #ooc_b 16 アドレス変換 Address Translation 論理アドレス MMU Memory Management

    Unit TLB Translation Look-aside Buffer 物理アドレス • アドレス変換は CPU 内の専用ハードウェアが行う • アドレス変換情報は TLB によってキャッシュされる • TLB にキャッシュがない場合はページテーブルを参照する(ページウォーク) DDR Controller
  6. #ooc_2020 #ooc_b 17 アドレス変換 Address Translation x64 ( AMD64 /

    Intel64 ) アーキテクチャにおいて、 • OS <-> RAM 間は 64bit 単位で読み書きされる • メモリアドレスは 48bit ( 最大 256TB ) で表されている • メモリ要求量に応じて 4 KB / 2 MB / 1 GB ごとに区切られたページが確保される • 仮想~物理アドレスの対応はページテーブルで管理される • 頻繁に使われるアドレスは TLB ( Translation Look-aside Buffer ) にキャッシュされる • ページテーブルは OS* が定義してメモリに格納するが、動作は CPU の機構 * GDT ( Global Descriptor Table ) の一部として定義される
  7. #ooc_2020 #ooc_b 19 メモリアロケータ Memory Allocator glibc malloc() プログラム Main

    Arena Arena chunk chunk chunk fastbins[] bins[] ※かなり簡略化しています top next
  8. #ooc_2020 #ooc_b 20 メモリアロケータ Memory Allocator glibc malloc() • 確保したいメモリサイズに応じて自動で最適なサイズを割り当てる

    • 確保したいメモリサイズごとに異なる領域 ( fastbins, bins ) をもつ ◦ fastbins <= 160 bytes ◦ bins > 160 bytes • 大きなメモリ ( >= M_MMAP_THRESHOLD ) は mmap 命令で確保する • free しても内部的にはキャッシュのため解放されない場合がある • chunk 単位でメモリを確保・管理する • chunk は 8 バイトでアラインメントされている • 詳しい実装は この辺り を参考に
  9. #ooc_2020 #ooc_b 21 メモリアロケータ Memory Allocator 有名なメモリアロケータ • glibc malloc

    • TCmalloc ( Google ) • mimalloc ( Microsoft ) • jemalloc • nedmalloc
  10. #ooc_2020 #ooc_b 22 アラインメント Alignment 型 メモリ(バイト) short 2 int

    4 float 4 double 8 char 1 一般的なデータ型のメモリ使用量 struct Person { char age; / / 1 byte int gender; / / 4 bytes short height; / / 2 bytes double weight; / / 8 bytes }; 実際は何バイト使われる?
  11. #ooc_2020 #ooc_b 0 ( bytes ) 8 16 24 23

    アラインメント Memory Alignment 未使用領域 アライメント ( Alignment ) メモリ使用境界をキャッシュライン(アクセスに最適なサイズ境界)にあわせること • アクセスに無駄がなく高速に読み書きできる • CPUによってはアラインメント違反はエラーになる • 未使用領域が発生する
  12. #ooc_2020 #ooc_b height 24 アラインメント Alignment gender weight age 0

    4 8 16 1 アライメント最適化 • 各言語コンパイラがフィールド並び順を最適化するなど工夫している • 最適化の限界はキャッシュライン+高級言語の仕様次第
  13. #ooc_2020 #ooc_b 25 メモリの分類 Stack and Heap BSS DATA TEXT

    基本的なメモリの分類 スタック • 確保・解放が高速 • 寿命が短い ( LIFO ) • サイズが小さい ◦ ulimit -s ( Default 8MB ) ヒープ • 確保・解放が低速 • 寿命が自由 • サイズが大きい Shared Heap Stack
  14. #ooc_2020 #ooc_b 26 スタックとヒープ Stack and Heap 参照型変数 Object b

    ローカル変数 int c = 1; ローカル変数 int d = 2; Object() 実体 Object() 実体 参照型変数 Object a スタック ヒープ 値をもつ
  15. #ooc_2020 #ooc_b 27 スタックとヒープ Stack and Heap f2() int data

    = 0; f1() int data = 0; global f3() int data = 0; コールスタック ( Call Stack ) 関数用に確保されたエリアで、 「関数スタック」ともいう。 呼び出し順に積み上げられて、 リターン時に自動破棄される。 • ローカル変数/引数 • RBP • リターンアドレス 格納する箱の単位を「スタック フレーム」という。 global f1() f2() f3() 呼び出し順序
  16. #ooc_2020 #ooc_b 28 Stack and Heap スタックとヒープ hoge fuga Arena

    Arena ヒープ ( Heap ) いつでも自由に数KB~数GB単位の 大きなメモリ領域を確保し、必要な 時間だけ占有できる。 使用後は必ず誰かが解放する。
  17. #ooc_2020 #ooc_b 29 まとめ Conclusion • CPU 内で一度に処理できるデータは 64bit (

    x64 ) • メモリとの読み書きを頻繁に繰り返している ◦ 高速に保つため CPU 内で n 次キャッシュをもつ ◦ アクセス速度はバスクロック/メモリクロックに依存する • オブジェクトで管理されるメモリ領域はアラインメントされる • 引数やローカル変数は高速なスタック領域に確保される • グローバル変数など長期間使用する場合はヒープ領域に確保される • 大きなオブジェクトのメモリ確保は相対的に重い
  18. #ooc_2020 #ooc_b 33 PHP 5.x Shape of Object ZVAL構造体 [

    php-src/Zend/zend.h#L334 ] 項目 内容 refcount 参照カウンタ type 型を示す文字列 ( Type specifier ) is_ref 参照集合かどうかを判定するBool値
  19. #ooc_2020 #ooc_b $ php hoge.php name: (interned, is_ref=0)='@ariaki4dev' hello: (refcount=1,

    is_ref=0)='Hello, @ariaki4dev' 35 PHP 7.x Shape of Object ZVALの内容確認(※要xdebug) • interned:文字列がインターン化された状態 • refcount:参照カウンタ • is_ref:参照の有無
  20. #ooc_2020 #ooc_b 36 PHP 7.x Shape of Object 0 0

    0 a: (interned, is_ref=0)='test' b: (refcount=0, is_ref=0)=1234 c: (refcount=2, is_ref=0)=array ( 0 => (interned, is_ref=0)='a', 1 => (interned, is_ref=0)='b', 2 => (interned, is_ref=0)='c' ) インターン化 同じ文字列を共通領域に保管し、個別に メモリを確保せず参照する。 数値など他の型は対象外。
  21. #ooc_2020 #ooc_b $ php hoge.php name: (refcount=2, is_ref=1)='@ariaki4dev' account: (refcount=2,

    is_ref=1)='@ariaki4dev' 37 PHP 7.x Shape of Object ZVALの内容確認(※要xdebug)
  22. #ooc_2020 #ooc_b 41 コピーオンライト Copy-On-Write • $ar1 → $ar2 にコピーされた時点では

    $ar2 のメモリは確保されない • $ar2[0] がセットされた時点で値が複製 ( Copy-on-Write ) される • 参照カウンタをもちいて refcount > 1 の場合に複製を実行する
  23. #ooc_2020 #ooc_b 43 PHP 7.x Shape of Object 配列をいじめる(※要xdebug) 0

    376 376 696 8 個ごとにメモリを追加確保している?! スタックから追い出された?!
  24. #ooc_2020 #ooc_b 44 PHP 7.x Shape of Object オブジェクトをいじめる(※要xdebug) 40

    96 a: (refcount=1, is_ref=0)=class stdClass { } b: (refcount=1, is_ref=0)=class stdClass { }
  25. #ooc_2020 #ooc_b 47 PHP 7.x Shape of Object オブジェクトをいじめる(※要xdebug) 56

    80 96 オーバーライドでメモリを別途確保してる
  26. #ooc_2020 #ooc_b 48 PHP 7.x Shape of Object オブジェクトをいじめる(※要xdebug) 100

    万回継承した結果 • 使用メモリは変わらず 40 バイト • ルートクラスの継承を確認できた • 重かった(手元の PC で 8 秒位)
  27. #ooc_2020 #ooc_b 49 Java VM Shape of Object Object Header

    ( 128bit ) unused (25) thread (54) ptr_to_lock_record (62) ptr_to_heavyweight_monitor (62) OOP to metadata object OOP to metadata object OOP to metadata object OOP to metadata object OOP to metadata object Normal Biased Lightweight Locked Heavyweight Locked Marked for GC ( State ) Mark Word ( 64bit ) lock (2) lock (2) lock (2) lock (2) lock (2) epoch (2) unused (1) age (4) biased_lock (1) Klass Word ( 64bit ) unused (1) age (4) biased_lock (1) identity_hashcode (31) Java x64 ヘッダ構造
  28. #ooc_2020 #ooc_b 50 Java VM Shape of Object オブジェクトロックの種類 •

    Biased Lock ◦ 単一スレッドがロックを占有 → 他スレッドから revoke ( Stop the World ) ◦ Java 6 以降で標準採用 • Lightweight Lock ( thin lock ) ◦ CAS ( Compare-and-Swap ) を用いたロック ◦ 楽観的 ( optimistic ) ロック • Heavyweight Lock ( fat lock ) ◦ OS のロック関数 ( pthread_mutex_lock) を用いたロック ◦ 悲観的 ( pessimistic ) ロック
  29. #ooc_2020 #ooc_b 51 Java VM Shape of Object 悲観的ロック (

    Pessimistic Lock ) 楽観的ロック ( Optimistic Lock )
  30. #ooc_2020 #ooc_b 52 Java VM Shape of Object -XX :

    UseCompressedOops • Java 6 以降、標準で有効になっている • Klass Word を 32bit に圧縮する • 手動で無効にすることもできる • -Xmx32767m ( 32 GB ) 以上の場合、自動で無効になる ◦ 大量メモリ割当が非効率といわれる原因のひとつ
  31. #ooc_2020 #ooc_b 53 Java VM Shape of Object オブジェクトのメモリ配置 •

    すべてのオブジェクトは 8 バイト境界に配置される • クラス変数は次のように並び替えられる ◦ long, double → int, float → char, short → byte, boolean → 参照型 • 変数はそれぞれのバイト境界に配置される • 階層の異なるクラスのフィールドは混合配置しない(親クラス→子クラス) • 親クラスの最終フィールド後は 4 バイト境界にあわせる • 子クラスの先頭フィールドが long, double かつ親クラスが 8 バイト境界以外の場合、 節約のため他の型を先頭に配置する
  32. #ooc_2020 #ooc_b 54 Java VM Shape of Object 省メモリ戦略 •

    参照型をできる限り減らす ◦ String → char[] ◦ プリミティブ型にする(例:Boolean → boolean ) • 大量のフラグを BitSet へ • コレクションを減らす ( HashSet, HashMap, etc. ) • Generics 等による AutoBoxing に気をつける • 省メモリライブラリを使用する ◦ FastUtil / Eclipse Collections / hppc / Koloboke / Trove / など
  33. #ooc_2020 #ooc_b 55 Java VM Shape of Object メモリ使用量の計測 •

    Instrumentation.getObjectSize(object) • Runtime.getRuntime().totalMemory() / freeMemory() • RamUsageEstimator.sizeOf() / hppc • jstat
  34. #ooc_2020 #ooc_b 56 Java VM Shape of Object JOL (

    Java Object Layout ) - http:/ /openjdk.java.net/projects/code-tools/jol/ $ java -jar jol-cli/target/jol-cli.jar footprint java.util.Hashtable Running 64-bit HotSpot VM. Using compressed oop with 3-bit shift. Using compressed klass with 3-bit shift. Objects are 8 bytes aligned. Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes] java.util.Hashtable instance footprint: COUNT AVG SUM DESCRIPTION 1 64 64 [Ljava.util.Hashtable$Entry; 1 48 48 java.util.Hashtable 2 112 (total)
  35. #ooc_2020 #ooc_b 57 Java VM Shape of Object Header boxes[0]

    boxes[1] width Header height width Header height 現在の配列構造 無駄なヘッダ
  36. #ooc_2020 #ooc_b 58 Java VM Shape of Object Header boxes[0]

    boxes[1] width height width height 理想の配列構造 boxes[2] width height Project Valhalla Value Types プリミティブ型と同じ挙動をす る任意の型を定義できる Generic Specialization ジェネリクスに対しプリミティ ブ型引数によるインスタンス化 をサポートする https:/ /openjdk.java.net/projects/valhalla
  37. #ooc_2020 #ooc_b 59 Golang Shape of Object Golang のメモリ割り当て •

    コンパイラが判断して自動的にスタック/ヒープを振り分ける ◦ 基本的にはスタックを優先して使い、開発者が割当先を気にする必要はない ◦ newしてもメソッド内で完結するものはスタック割当 ◦ ローカル変数のポインタを外に持ち出す場合はヒープ割当 ◦ どちらに振り分けられるかはビルドオプション ( -gcflags -m ) で確認できる • メモリ管理には TCMalloc ( Google ) を使っている ◦ 32KB 以下は個別管理、超えるものは共有管理 • goroutine は標準で 2KB のスタック を確保する ◦ 必要に応じてスタックサイズが拡張される ◦ スタックプールを用いて、未使用のスタックをキャッシュする
  38. #ooc_2020 #ooc_b 60 まとめ Conclusion • メモリ確保や使用方法は、それぞれ言語によって最適化されている • クラスが階層化する場合、レイヤごとに属性が保持される •

    オブジェクトヘッダ仕様は言語の設計思想が強く反映される • オブジェクトの振る舞いやその理由を調べるのは楽しい
  39. #ooc_2020 #ooc_b 62 Garbage Collection Overview GC ( Garbage Collection

    ) • 不要になったメモリ領域を自動で回収する仕組み ◦ それまではメモリ管理はすべて手動(確保~使用~解放)だった ◦ 手動管理はあまりにも煩雑 • 1960 年に John McCarthy によってはじめて論文が発表された ◦ 最初の仕組みはマークアンドスイープ ( Mark & Sweep ) ◦ LISP に実装された • メモリ使用に注力し、確保と解放を自動化できる • 今日では主要な言語ほぼすべてに採用されている ◦ 多くの言語で GC 動作中の動作停止 ( STW: Stop the World ) が発生する
  40. #ooc_2020 #ooc_b 63 Garbage Collection Overview タイミングとメモリリーク • GC はメモリ使用量などが一定の閾値を超えた場合に実行される

    ◦ マイナーGC ◦ メジャーGC(フルGC) • 複雑なプログラム構造からメモリの解放漏れ(メモリリーク)が発生する ◦ 循環参照 ◦ クロージャ ◦ 意図しないグローバル変数 ◦ タイマーやコールバックなどの増殖 など
  41. #ooc_2020 #ooc_b 64 Garbage Collection Overview 代表的なアルゴリズム 方式 説明 参照カウント

    オブジェクトの参照数がゼロのものを削除する マークアンドスイープ 未使用のオブジェクトをマークした後に削除する マークアンドコンパクト 未使用のオブジェクトをマークした後に削除して詰める コピー 使用中のオブジェクトを別空間に移動して切り替える
  42. #ooc_2020 #ooc_b 65 GC in PHP Garbage Collection inside Languages

    a: (refcount=1, is_ref=0)=class stdClass { } a: (refcount=2, is_ref=0)=class stdClass { } a: (refcount=1, is_ref=0)=class stdClass { } a: no such symbol
  43. #ooc_2020 #ooc_b 66 GC in PHP Garbage Collection inside Languages

    a: (refcount=1, is_ref=0)=class stdClass { } b: (refcount=1, is_ref=0)=class stdClass { } a: (refcount=2, is_ref=0)=class stdClass { ... } b: (refcount=2, is_ref=0)=class stdClass { ... } a: (refcount=2, is_ref=0)=class stdClass { …. } b: no such symbol a: no such symbol b: no such symbol
  44. #ooc_2020 #ooc_b 68 GC in PHP Garbage Collection inside Languages

    80 864 864 32 オブジェクトが循環参照している
  45. #ooc_2020 #ooc_b 69 GC in PHP Garbage Collection inside Languages

    80 864 864 32 参照カウントがなくなっても回収されない
  46. #ooc_2020 #ooc_b 70 GC in PHP Garbage Collection inside Languages

    80 864 864 32 強制GCによって回収された
  47. #ooc_2020 #ooc_b 71 GC in PHP Garbage Collection inside Languages

    GC in PHP • 参照カウント方式で GC が動作する ◦ 循環参照オブジェクトも正しく回収される ◦ PHP 5.2 以前は循環参照が回収されないので注意(誰も使ってないはず) • 表面上は unset() 等で即座にアクセスできなくなる • オブジェクトが閾値 ( 10,000 件 ) に達するまで回収されない • PHP 7.4 より弱参照 ( WeakReference ) が実装された ◦ GC による回収を阻害しないオブジェクト ◦ メモリリークを防いだりキャッシュなどに利用
  48. #ooc_2020 #ooc_b 73 三色マーキング Tricolor Marking 灰色オブジェクト 白色オブジェクト • コレクターが到達し、全フィールド走査していないオブジェクト

    • 生存可否が未確定の状態 • 全走査完了後に灰色は残らない • コレクターが未到達のオブジェクト • 処理終了後に白色の場合は回収される 黒色オブジェクト • コレクターが全フィールドに到達済みのオブジェクト • 生存が確定し、これ以上走査の必要はない
  49. #ooc_2020 #ooc_b 74 三色マーキング Tricolor Marking 三色マーキングの手順 1. すべてのオブジェクトが白色状態 2.

    ルートオブジェクトをすべて走査し、到達したものを灰色に設定する 3. ルートオブジェクトの内部オブジェクトを繰り返し走査する 4. 内部探索が終わったオブジェクトを黒色に設定する 5. すべての探索が終了後、灰色は残らず黒/白いずれかになる
  50. #ooc_2020 #ooc_b 75 三色不変条件 Tricolor Invariants 弱い三色不変条件 ( the weak

    tricolor invariants ) 黒いオブジェクトから参照するすべてのオブジェクトが灰色保護されている 強い三色不変条件 ( the strong tricolor invariants ) 黒いオブジェクトから参照する白いオブジェクトが存在しない $a $b $a $b ( 参考:https:/ /www.slideshare.net/y-uti/php-gc )
  51. #ooc_2020 #ooc_b 76 GC in Java Garbage Collection inside Languages

    $ java Demonstration Foundation Constructor Demonstration Constructor Demonstration Destructor Foundation Destructor ※ System.gc() および finalize() メソッドは非推奨
  52. #ooc_2020 #ooc_b 77 GC in Java Garbage Collection inside Languages

    $ java Demonstration Foundation Constructor Demonstration Constructor
  53. #ooc_2020 #ooc_b 78 GC in Java Garbage Collection inside Languages

    VM Heap VM Stack From To Eden Survivor New ( Nursery ) Old ( Tenured ) Permenent Java メモリ管理 Java には多くの GC 機構が取り入れられている • 世代別 GC • コピー GC / コンパクション • マークスイープ GC
  54. #ooc_2020 #ooc_b 79 GC in Java Garbage Collection inside Languages

    VM Heap VM Stack From To Eden Survivor New ( Nursery ) Old ( Tenured ) Permenent GC の仕組み 新しいオブジェクトをEden領域に割り当て
  55. #ooc_2020 #ooc_b 80 GC in Java Garbage Collection inside Languages

    VM Heap VM Stack From To Eden Survivor New ( Nursery ) Old ( Tenured ) Permenent GC の仕組み Minor Garbage Collection (1) 不要データを削除 (2) 必要データを Eden → To に移動
  56. #ooc_2020 #ooc_b 81 GC in Java Garbage Collection inside Languages

    VM Heap VM Stack From To Eden Survivor New ( Nursery ) Old ( Tenured ) Permenent GC の仕組み Minor Garbage Collection (1) To → From を入れ替える
  57. #ooc_2020 #ooc_b 82 GC in Java Garbage Collection inside Languages

    VM Heap VM Stack From To Eden Survivor New ( Nursery ) Old ( Tenured ) Permenent GC の仕組み Minor Garbage Collection (1) To → From を入れ替える (2) 不要データを削除 (3) 必要データを Eden / From → To に移動
  58. #ooc_2020 #ooc_b 83 GC in Java Garbage Collection inside Languages

    VM Heap VM Stack From To Eden Survivor New ( Nursery ) Old ( Tenured ) Permenent GC の仕組み Minor Garbage Collection (1) To → From を入れ替える (2) 不要データを削除 (3) 必要データを Eden / From → To に移動 (4) 年齢が一定に達したものを Old に移動
  59. #ooc_2020 #ooc_b 84 GC in Java Garbage Collection inside Languages

    VM Heap VM Stack From To Survivor New ( Nursery ) Permenent GC の仕組み Full Garbage Collection • Old へのメモリ割り当てが失敗した場合 • Young / Old 両方を対象とした回収処理 • Old からの退避領域はないため特殊な GC Eden Old ( Tenured )
  60. #ooc_2020 #ooc_b Eden 領域が不足している場合 直接 Old 領域にオブジェクトが格納される 85 GC in

    Java Garbage Collection inside Languages VM Heap VM Stack From To Eden Survivor New ( Nursery ) Old ( Tenured ) Permenent GC の仕組み
  61. #ooc_2020 #ooc_b 86 GC in Java Garbage Collection inside Languages

    Out Of Memory Exception • オブジェクト格納先メモリを確保できない • GC が頻繁に発生しすぎた • GC による回収領域が小さすぎた • Permanent 領域が枯渇した など
  62. #ooc_2020 #ooc_b 87 GC in Java Garbage Collection inside Languages

    Initial Mark Concurrent Mark & Preclean Remark Concurrent Sweep & Reset StW StW GC Thread Application Thread Concurrent Mark and Sweep ( Write Barrier )
  63. #ooc_2020 #ooc_b 88 GC in Java Garbage Collection inside Languages

    Appendix - Java GC に関する有益な資料 • https:/ /gihyo.jp/dev/serial/01/jvm-arc/0004 • https:/ /blog.cybozu.io/entry/2018/05/29/080000 • https:/ /wiki.openjdk.java.net/display/shenandoah/Main • https:/ /www.infoq.com/jp/news/2019/05/java12-released/ • https:/ /www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-MA16-GC.pdf • http:/ /www.nminoru.jp/~nminoru/java/cms/concurrent_mark_sweep.html
  64. #ooc_2020 #ooc_b 91 ORG 0x7c00 JMP SHORT entry DB 0x90

    DB "STARTIPL" DW 512 DB 1 DW 1 DB 2 DW 224 DW 2880 DB 0xf0 DW 9 DW 18 DW 2 DD 0 DD 2880 DB 0,0,0x29 DD 0xffffffff DB "TESTIPLDISK" DB "FAT12 " TIMES 18 DB 0 entry: MOV ax, 0 MOV ss, ax MOV sp, 0x7c00 MOV ds, ax MOV es, ax MOV si, msg putloop: MOV al, [si] ADD si, 1 CMP al, 0 JE fin MOV ah, 0x0e MOV bx, 15 INT 0x10 JMP putloop fin: HLT JMP fin msg: DB 0x0a, 0x0a DB "Hello, World" DB 0x0a DB 0 TIMES 0x1fe-($-$$) DB 0 DB 0x55, 0xaa DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 TIMES 4600 DB 0 DB 0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 TIMES 1469432 DB 0 HELLO.IPL ( nasm )
  65. #ABDCFF - #0396FF #CE9FFC - #7367F0 #81FBB8 - #28C76F #FF96F9

    - #C32BAC #4b4b4b 98 Learn about Object Lifecycle & Memory Management Object-Oriented Conference 2020 #ooc_2020