More Related Content
PDF
PDF
PDF
PDF
中3女子が狂える本当に気持ちのいい constexpr PDF
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ PPT
PDF
組み込み関数(intrinsic)によるSIMD入門 PDF
Pythonの理解を試みる 〜バイトコードインタプリタを作成する〜 What's hot
PDF
PDF
PDF
PDF
CEDEC 2018 最速のC#の書き方 - C#大統一理論へ向けて性能的課題を払拭する PDF
PDF
C# ゲームプログラミングはホントにメモリのことに無頓着でいいの? PDF
PDF
PDF
PDF
20分くらいでわかった気分になれるC++20コルーチン PDF
PDF
ARM CPUにおけるSIMDを用いた高速計算入門 PDF
PDF
PPTX
PDF
PDF
PDF
PDF
PDF
Viewers also liked
PDF
PDF
PDF
PDF
PPT
PDF
PDF
Exploring the Performance Impact of Virtualization on an HPC Cloud PDF
PPTX
[学内勉強会]C++11とdirectxライブラリ PDF
PPT
PDF
PDF
PDF
PPTX
PDF
クラウドの垣根を超えた高性能計算に向けて~AIST Super Green Cloudでの試み~ PDF
Similar to マーク&スイープ勉強会
PPTX
PPTX
PPTX
PDF
PDF
PDF
PDF
C++0x in programming competition PPTX
Introduction to programming PDF
Precise garbage collection for c PDF
PPTX
PPT
PPT
PDF
PDF
PDF
“Adoption and Focus: Practical Linear Types for Imperative Programming”他の紹介@P... PDF
PDF
ODP
ODP
More from 7shi
PDF
PDF
PDF
PDF
V6 Interpreter (Nagoya Geek Bar 2011-05-02) PDF
PPT
Recently uploaded
PDF
自転車ユーザ参加型路面画像センシングによる点字ブロック検出における性能向上方法の模索 (20260123 SeMI研) PDF
第21回 Gen AI 勉強会「NotebookLMで60ページ超の スライドを作成してみた」 PDF
2025→2026宙畑ゆく年くる年レポート_100社を超える企業アンケート総まとめ!!_企業まとめ_1229_3版 PDF
ST2024_PM1_2_Case_study_of_local_newspaper_company.pdf PDF
PMBOK 7th Edition_Project Management Context Diagram PDF
PMBOK 7th Edition Project Management Process Scrum PDF
100年後の知財業界-生成AIスライドアドリブプレゼン イーパテントYouTube配信 PDF
Team Topology Adaptive Organizational Design for Rapid Delivery of Valuable S... PDF
Starlink Direct-to-Cell (D2C) 技術の概要と将来の展望 PDF
FY2025 IT Strategist Afternoon I Question-1 Balanced Scorecard PDF
Reiwa 7 IT Strategist Afternoon I Question-1 3C Analysis PDF
Reiwa 7 IT Strategist Afternoon I Question-1 Ansoff's Growth Vector PDF
PMBOK 7th Edition_Project Management Process_WF Type Development マーク&スイープ勉強会
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
変数探し
• スタックフレームを走査して変数を検出
#include <stdio.h>
voidsearch(int *start, int value) {
for (int *p = start; p > &value; p--) {
if (*p == value) {
printf("found: %p¥n", p);
return;
}
}
}
int main(int argc, char *argv[]) {
int a = 0xcafebabe;
printf("&a: %p¥n", &a);
search(&argc, a);
}
&a: 0028FF1C
found: 0028FF1C
実行結果
- 13.
malloc (1)
• 冒頭の問題に戻る
#include<stdlib.h>
int main() {
void *a = malloc(10);
void *b = malloc(10);
a = NULL;
}
• malloc() の戻り値を記録しておいて、スタック
フレームに含まれるか確認すれば良い
- 14.
malloc (2)
• malloc()の戻り値を記録する例
#include <stdlib.h>
#include <map>
static std::map<void *, bool> mallocs;
void *gc_malloc(size_t size) {
void *ret = malloc(size);
mallocs[ret] = true;
return ret;
}
- 15.
問題 1
• 以下のコードで使われているgc_init(),
gc_malloc(), gc_collect() を実装してください。
• ※ 最初に掲示した問題を改変しました。
#include <stdlib.h>
int main(int argc, char *argv[]) {
gc_init(&argc);
void *a = gc_malloc(10);
void *b = gc_malloc(10);
a = NULL;
gc_collect();
}
- 16.
問題 1 の回答例
staticvoid **stack_start;
void gc_init(int *pargc) {
stack_start = reinterpret_cast<void **>(pargc);
}
void gc_collect() {
void *end;
for (auto it = mallocs.begin(); it != mallocs.end(); ++it)
it->second = false;
for (auto p = stack_start; p > &end; p--)
if (mallocs.find(*p) != mallocs.end())
mallocs[*p] = true;
for (auto it = mallocs.begin(); it != mallocs.end();)
if (it->second) ++it; else {
free(it->first);
mallocs.erase(it++);
}
}
- 17.
- 18.
- 19.
- 20.
問題 2
• 生きている領域が解放されないようにGCを
修正してください。
#include<stdlib.h>
struct Test { void *ptr; };
int main(int argc, char *argv[]) {
gc_init(&argc);
Test *t = reinterpret_cast<Test *>(
gc_malloc(sizeof(Test)));
t->ptr = gc_malloc(10);
gc_collect();
} 生きているのに
回収されてしまう!
- 21.
問題 2 の回答例(抜粋)
structHeapInfo { size_t size, sizep; bool marked; };
static std::map<void *, HeapInfo> mallocs;
void *gc_malloc(size_t size) {
void *ret = malloc(size);
HeapInfo hi = { size, size / sizeof(void *), true };
mallocs[ret] = hi;
return ret;
}
static void gc_scan(void **start, void **end) {
for (auto p = start; p < end; p++) {
auto it = mallocs.find(*p);
if (it != mallocs.end() && !it->second.marked) {
it->second.marked = true;
auto pp = reinterpret_cast<void **>(*p);
gc_scan(pp, pp + it->second.sizep);
}
}
}
- 22.
問題 3
• 無駄なスキャンを抑制してください。
structTest { void *ptr; int *buf; };
int main(int argc, char *argv[]) {
gc_init(&argc);
Test *t = reinterpret_cast<Test *>(
gc_malloc(sizeof(Test)));
t->ptr = gc_malloc(10);
t->buf = reinterpret_cast<int *>(
gc_malloc(1024 * 1024));
gc_collect();
} ポインタが含まれていない
内部の走査は無駄!
- 23.
問題 3 の回答例(抜粋)
•内部を走査するか指定できるようにする
struct HeapInfo { size_t size, sizep; bool marked, scan; };
void *gc_malloc(size_t size, bool scan = true) { 略 }
static void gc_scan(void **start, void **end) {
略
it->second.marked = true;
if (it->second.scan) { 略 }
略
}
int main(int argc, char *argv[]) {
略
t->buf = reinterpret_cast<int *>(
gc_malloc(1024 * 1024, false));
gc_collect();
}
- 24.
- 25.
new (1)
• 以前出てきた例を改めて見返すと・・・
#include<stdlib.h>
struct Test { void *ptr; };
int main(int argc, char *argv[]) {
gc_init(&argc);
Test *t = reinterpret_cast<Test *>(
gc_malloc(sizeof(Test)));
t->ptr = gc_malloc(10);
gc_collect();
} いくら何でも冗長過ぎる!
newで簡単に書けないか?
- 26.
new (2)
• operatornewを置き換えると無条件にGC対
象となってしまうため、意図的にGCを外した
いときに不便
• newした後、GCに登録する関数を用意
• 常にGC対象にしたいクラスはコンストラクタ
で自分を登録すれば良い
Test *t = gc_register(new Test);
struct Test {
Test() { gc_register(this); }
};
- 27.
new (3)
• deleteで解放するため、解放処理をコール
バックとして登録できるようにする
•free() と同じ型の関数ポインタで登録するた
め、delete のラッパーを用意
template <class T> void gc_delete(void *p) {
delete reinterpret_cast<T *>(p);
}
template <class T> void gc_delete_array(void *p) {
delete [] reinterpret_cast<T *>(p);
}
- 28.
実装例(抜粋)
struct HeapInfo {
size_tsize, sizep; bool marked, scan;
void (*free)(void *);
};
void gc_register(void *p, size_t size, bool scan,
void (*free)(void *)) {
HeapInfo hi = { size, size / sizeof(void *),
true, scan, free };
mallocs[p] = hi;
}
void *gc_malloc(size_t size, bool scan = true) {
void *ret = malloc(size);
gc_register(ret, size, scan, free);
return ret;
}
template <class T> T *gc_register(T *t) {
gc_register(t, sizeof(T), true, gc_delete<T>);
return t;
}
- 29.
- 30.
- 31.
実装例(抜粋)
static std::list<void **>gc_ptrs;
template <class T> class gc_ptr {
T *ptr;
std::list<void **>::iterator it;
void init(T *p) {
ptr = p;
gc_ptrs.push_back(reinterpret_cast<void **>(&ptr));
it = --gc_ptrs.end();
}
public:
gc_ptr() { init(NULL); }
gc_ptr(const gc_ptr<T> &p) { init(p.ptr); }
gc_ptr(T *p) { init(p); }
~gc_ptr() { gc_ptrs.erase(it); }
gc_ptr<T> &operator =(T *p) { ptr = p; return *this; }
inline operator T *() const { return ptr; }
};
- 32.
- 33.
- 34.
クロージャ (3)
• ヒープを使う方式は、ローカル変数のキャプ
チャに参照を使うF# と同じ構造
• ヒープへのポインタを値束縛することで、環境
を閉じ込めたように見せかけている
std::function<int()> test() {
gc_ptr<int> a = gc_new<int>();
*a = 0;
return [=] { return ++(*a); };
}
C++ with GC
let test () =
let a = ref 0
fun () -> a := !a + 1; !a
F#
- 35.
- 36.
閾値 (1)
• 今までは手動でgc_collect を呼んでいた
• GCに登録するときに使用メモリ量をカウント
して、閾値を超えたら呼ぶことで自動化
static size_t mem_used;
static size_t threshold = 1024 * 1024;
void gc_register(void *p, size_t size, bool scan,
void (*free)(void *)) {
HeapInfo hi = { size, size / sizeof(void *),
true, scan, free };
mallocs[p] = hi;
mem_used += size;
if (mem_used > threshold) gc_collect();
}
- 37.
閾値 (2)
• スイープの際に使用メモリ量を減らす
•最終的に確定した使用量で閾値を調整
void gc_collect(void *dummy) {
略
for (auto it = mallocs.begin(); it != mallocs.end();) {
if (it->second.marked) ++it; else {
printf("sweep: %p¥n", it->first);
(*it->second.free)(it->first);
mem_used -= it->second.size;
mallocs.erase(it++);
}
}
while (mem_used > (threshold >> 1))
threshold <<= 1;
}
- 38.
閾値 (3)
• 自動的にgc_collect() が呼ばれるようになる
int main(int argc, char *argv[]) {
gc_init(&argc);
for (int i = 0; i < 10; i++)
gc_malloc(300 * 1024, false);
}
• 処理内容によってGCの特性は異なる
– 巨大なサイズが少数確保される場合
– 小さいサイズが大量に確保される場合
• サイズや個数も考慮すると効率が上がる
- 39.