読者です 読者をやめる 読者になる 読者になる

OSX El-Capitan にemacs 24.5 をインストールする

本記事は備忘録です

OSX El-Capitan にemacs 24.5 をインストールしました。幾つかの手順があるようですが、homebrew 経由でインストールしたい、かつinline パッチを当てるための作業が面倒だったこともあり、参考URL の"24.5 " の欄に記載の通りで上手くインストール出来ました。

過去にはinline パッチがマージされていた(-japanese を付与して発動)と記憶していますが、どうやらバージョンが変わると一旦戻ってしまうようですね。

参考URL

Homebrew/emacs - src's wiki

DigitalOcean にUbuntu with Fluentd な環境をVagrant で構築する

はじめに

タイトルの通りのことをやりました、というだけのエントリー。個人的にはVagrant を使った環境構築をやってみたかったという動機が強く、 詳しく知っている人にとってはあまりにも稚拙な内容であると思われるのでそっ閉じ推奨。

DigitalOcean はSSD を採用したVPS サービスで、時間(Hour)単位の課金が選択できるところが特徴的である。

https://www.digitalocean.com/:DigitalOcean

ここにUbuntu14.04 を立てて、ついでにFluentd をインストールするところまでをローカル環境のVagrant コマンド一発でできるようにする。

Vagrant をインストールする

Vagrant は手元の環境にインストールする必要がある。以下の例はローカル環境もUbuntuであることを想定している。

Vagrant 公式サイト からバイナリファイルをダウンロードする。今回は.deb ファイルである。

Vagrant

インストールする。ついでにDigitalOcean 用のプラグインも追加する。

 $ sudo dpkg -i ~/Downloads/vagrant_1.6.3_x86_64.deb
 $ vagrant plugin install vagrant-digitalocean

Vagrantfile を記述する

Vagrant コマンドに食わせるVagrantfile を書く。Vagrant は、このファイルの通りにDigitalOcean にDroplet(インスタンス)を立ち上げる。

Vagrantfile for Ubuntu14.04 with Fluentd

  • 以下の点は個別に要編集
    • YOUR_CLIENT_IDYOUR_API_KEY は、API から取得
    • YOUR_SSH_KEY_NAME は、SSH Keys から取得
    • YOUR_TOKEN は、Apps & API のPersonal Access Token から取得

このVagrantfile のprovision の項目で、OS立ち上げ後の個別設定、ここではFluentd のインストールを行っている。

Vagrant コマンドでDroplet をスタートする

以下のコマンドでDroplet をスタートし、ログインする。

$ cd /your/Vagrantfile/dir
$ vagrant up --provider=digital_ocean --provision

--provision を付与することで、Vagrantfile に記載したFluentd のインストール項目が実施される。

立ち上げたDroplet にログインするためには以下のコマンド。

$ vagrant ssh

作業が終わったら、課金を止めるために以下のコマンドでDroplet を削除する。(データはすべて削除される)

$ vagrant destroy

おわりに

Vagrant を用いたDigitalOcean のデプロイを試した。

今回紹介したVagrantfile は以下のレポジトリで管理している。

zonomasa/Vagrantfiles · GitHub

Vagrant入門ガイド

Vagrant入門ガイド

入門Chef Solo - Infrastructure as Code

入門Chef Solo - Infrastructure as Code

参考にしたURL

jemalloc の解析機能

※この記事は3回シリーズのうちの一つ

jemalloc について調べたのでまとめた - zonomasaの日記

続 jemalloc について調べたのでまとめた(ビルドと組み込み方法) - zonomasaの日記

jemalloc の解析機能 - zonomasaの日記

photo by ed10vi

jemalloc のメモリ解析機能

jemalloc はそれ自身がいくつかのメモリ解析機能を持っている。コンパイルオプションと実行時オプション指定によりそれぞれON/OFFが可能な設計になっている。

外部ツールなどに比べ容易に、比較的高速に使用することができるこれらの機能についてまとめようと思う。

前回記事: jemalloc について調べたのでまとめた - zonomasaの日記 続 jemalloc について調べたのでまとめた(ビルドと組み込み方法) - zonomasaの日記

メモリリーク検出

jemalloc でのメモリリークとは、malloc() されて、free()されていないメモリブロックを指す。

void
leak_memory(void){
    char *ptr1, *ptr2;

    ptr1 = (char *)malloc(32);
    ptr2 = (char *)malloc(1024);

    return;
}

メモリリーク検出の出力

jemalloc では、プロセスの終了時にメモリリーク発生のサマリを表示してくれる。

<jemalloc>: Leak summary: 1024 bytes, 1 object, 3 contexts
<jemalloc>: Run pprof on "jeprof.9803.0.f.heap" for leak detail

これは1024byte のメモリブロックが1つ、free() されずにプロセスが終了したことを示す。

メモリリーク検出の使い方

メモリリークの検出を有効にするためは、jemalloc ライブラリのビルド時に以下のようにオプションを指定する。

$ ./configure --enable-prof
$ make

また、実行時にMALLOC_CONF環境変数に以下のオプションを指定して実行する。

MALLOC_CONF="prof_leak:true,prof:true,lg_prof_sample:1" LD_PRELOAD=./lib/libjemalloc.so myapp.exe

メモリ破壊検出(オーバーフロー検出)

いわゆるバッファーオーバーフローを検出してくれる。malloc() した領域をはみ出したアクセス(オーバーフロー)を行っていないかのチェックであり、メモリブロックの前後の領域が検査の対象となる。

    ptr = (char *)malloc(24);
    for (i = 0; i < 40; i++){
        ptr[i] = 'a';
    }
    free(ptr);

    ptr = (char *)malloc(24);
    for (i = 0; i > -8; i--){
        ptr[i] = 'b';
    }
    free(ptr);

メモリ破壊検出の出力

free() を呼び出した際にオーバーフローアクセスの検査が行われ、問題がある場合には以下のような出力が行われる。

<jemalloc>: Corrupt redzone 0 bytes after 0x2b0908c0f081 (size 32), byte=0x61
<jemalloc>: Corrupt redzone 1 byte after 0x2b0908c0f081 (size 32), byte=0x61
<jemalloc>: Corrupt redzone 2 bytes after 0x2b0908c0f081 (size 32), byte=0x61
<jemalloc>: Corrupt redzone 3 bytes after 0x2b0908c0f081 (size 32), byte=0x61

これは、32byte のメモリブロックの後ろ4byte が意図せず書き換えられていた、つまりオーバーフローアクセスが行われたことを示している。

以下、コード例と合わせてどのような出力がされるのかを見ていく。

ケース1
    /* Can not detect */
    ptr = (char *)malloc(3);
    for (i = 0; i < 8; i++){
        ptr[i] = 'a';
    }
    free(ptr);

↑これは検出することが出来ない例である。3byte のmalloc() は内部的には8byte として扱われるため、4-8byte 目までの書き込みはオーバーフローとして扱わない。この点は、glibc mallocMALLOC_CHECK_ に比べて検出能力的に劣る点であると言わざるを得ない。

ケース2
    ptr = (char *)malloc(3);
    for (i = 0; i < 9; i++){
        ptr[i] = 'b';
    }
    free(ptr);

↑これは9byte 目にたいして書き込みが行われるので、以下のような出力がされる。

<jemalloc>: Corrupt redzone 0 bytes after 0x2b0f58f5a100 (size 8), byte=0x32
ケース3
    ptr = (char *)malloc(24);
    for (i = 0; i < 40; i++){
        ptr[i] = 'a';
    }
    free(ptr);

24byte 確保に対して、40byte の書き込みをした場合。

<jemalloc>: Corrupt redzone 0 bytes after 0x2b387c731180 (size 32), byte=0x61
<jemalloc>: Corrupt redzone 1 byte after 0x2b387c731180 (size 32), byte=0x61
<jemalloc>: Corrupt redzone 2 bytes after 0x2b387c731180 (size 32), byte=0x61
<jemalloc>: Corrupt redzone 3 bytes after 0x2b387c731180 (size 32), byte=0x61
<jemalloc>: Corrupt redzone 4 bytes after 0x2b387c731180 (size 32), byte=0x61
<jemalloc>: Corrupt redzone 5 bytes after 0x2b387c731180 (size 32), byte=0x61
<jemalloc>: Corrupt redzone 6 bytes after 0x2b387c731180 (size 32), byte=0x61
<jemalloc>: Corrupt redzone 7 bytes after 0x2b387c731180 (size 32), byte=0x61
ケース4
    ptr = (char *)malloc(24);
    for (i = 0; i > -8; i--){
        ptr[i] = 'd';
    }
    free(ptr);

メモリブロックの前方向(メモリアドレスの若い方向)に対して書き込みを行った場合も検出可能である。出力文がbefore になっている。

<jemalloc>: Corrupt redzone 1 byte before 0x2b0908c0f081 (size 32), byte=0x64
<jemalloc>: Corrupt redzone 2 bytes before 0x2b0908c0f081 (size 32), byte=0x64
<jemalloc>: Corrupt redzone 3 bytes before 0x2b0908c0f081 (size 32), byte=0x64
<jemalloc>: Corrupt redzone 4 bytes before 0x2b0908c0f081 (size 32), byte=0x64
<jemalloc>: Corrupt redzone 5 bytes before 0x2b0908c0f081 (size 32), byte=0x64
<jemalloc>: Corrupt redzone 6 bytes before 0x2b0908c0f081 (size 32), byte=0x64
<jemalloc>: Corrupt redzone 7 bytes before 0x2b0908c0f081 (size 32), byte=0x64

メモリ破壊検出の使い方

メモリリークの検出を有効にするためは、jemalloc ライブラリのビルド時に以下のようにオプションを指定する。

$ ./configure --enable-prof
$ make

上記に加え、--enable-debug を指定すると、opt.abort がON になり、warning 相当の事象が起きた際にプログラムがabort する。

また、実行時にMALLOC_CONF環境変数に以下のオプションを指定して実行する。

MALLOC_CONF="redzone:true,prof:true"

double-free 検出

double-free は以下のようにfree() を同じポインタに対して2度(以上)行う処理である。

    char *ptr;

    ptr = (char *)malloc(32);

    free(ptr);
    free(ptr);

jemalloc ではこのdouble-freeを検出する機能を備えている

double-free の他にも、おかしなポインタをfree() に渡した場合にも同様の検出ができる。

double-free 検出の出力例

double-free は検出した瞬間にAssertがかかり、プログラムは停止する。

<jemalloc>: src/arena.c:321: Failed assertion: "bitmap_get(bitmap, &bin_info->bitmap_info, regind)"
Aborted (core dumped)

double-free 検出の使い方

double-free 検出を有効にするためは、jemalloc ライブラリのビルド時に以下のようにオプションを指定する。

$ ./configure --enable-debug
$ make

また、実行時にMALLOC_CONF環境変数に以下のオプションを指定して実行することが推奨されている。(私の環境ではこのオプションを指定しない場合、適切に検出出来なかった)

MALLOC_CONF="tcache:false"

おわりに

jemalloc シリーズ第3弾として、メモリ解析機能を紹介した。

これらの解析機能は他の多くのツールでも実現されているものである。使いどころ、オーバーヘッドなど、他のツールとの比較を行いたい。

続 jemalloc について調べたのでまとめた(ビルドと組み込み方法)

※この記事は3回シリーズのうちの一つ

jemalloc について調べたのでまとめた - zonomasaの日記

続 jemalloc について調べたのでまとめた(ビルドと組み込み方法) - zonomasaの日記

jemalloc の解析機能 - zonomasaの日記

photo by fotoamater.com

jemalloc の使い方

前回に引き続きjemallocについて調べたのでまとめる。今回は主に使用方法についてである。

前回記事: jemalloc について調べたのでまとめた - zonomasaの日記

jemalloc のインストール

3つのインストール方法を挙げるが、このあと詳細に説明するのは2. の方法である。 (1. も大きくは変わりません。最初にautoconf するかどうかの違い程度)

  1. canonware.com のStable バージョンを取得しビルドする
  2. Github から開発版を取得しビルドする
  3. Ruby アプリ限定)Github treasure-data/jemalloc-rb を利用する

Github から開発版を取得しビルドする

Github から取得し./configure && make && make install するだけである。ただし./configure の際にオプションを指定することで、jemallocの振る舞いを変えることができる。(後述)

Install jemalloc on Mac OSX

Linux の場合、最後の一行は$ sudo make install とするべきである。

これにより、Linux であれば/usr/local/lib/libjemalloc.so もしくは/usr/local/lib/libjemalloc.a がインストールされる。もちろん、make install 自体は必須ではない。後ほど説明する組み込み方法を見てもらえばわかるが、jemalloc を最もライトに使う方法はLD_PRELOAD を使うものであり、その範囲に限ればライブラリの置き場がどこでも良い。

./configure のオプション

./configure の際にはいくつかのオプションを取ることができる。これによりヒーププロファイリングなどの機能のON/OFF を行う。

ソースパッケージのINSTALL に記載されているオプションのうち、有用なものを列挙する。

jemalloc の有用なビルドオプション

これらのオプションに関わる機能を使用する方法は次回以降に具体的に紹介する。

jemalloc をアプリケーションに組み込む

さて、ここまででjemallocのライブラリわけだが、アプリケーションに組み込まなくてはいけない。ドラクエ風に言えば、make しただけでは意味がない。linkしないとな

前回も述べたとおり、jemalloc はmalloc() free() などの標準関数の置き換えと、jemalloc 独自の関数群を併せ持っており、それらの使い方によって組み込み方法も変わってくる。

ここでは3つの方法を挙げる。

  1. LD_PRELOAD 環境変数を用いる。動作時に標準関数malloc(), free(), realloc() などの関数をjemalloc に置き換える。
  2. ビルド時にリンクする。アプリケーションのリンクの段階でjemalloc をリンクする。標準関数も置き換えられ、さらにjemalloc 独自の関数群も使用できる。
  3. --with-jemalloc-prefix= でビルドし、標準関数とはことなる関数名にする。箇所によってjemalloc を使うかglibc を使うかを決めることができる。

1. は最も簡単な使い方となる。LD_PRELOAD で指定したライブラリは、動作時に最も優先してシンボルが探される。つまりglibcmalloc() の前に jemalloc のmalloc() が呼ばれる。

この方式の最も優れている点は、アプリケーションの再ビルドが不要であることだ。malloc() を使っているプログラムなら何でもいい。LD_PRELOAD で指定するだけで、jemalloc の恩恵に預かれる。

この恩恵が受けられるのはCプログラマに限った話ではない。Firefox などのリリースされたアプリケーションや、Rubyアプリケーション などの非C言語フレームワークに対しても適用できる。

2. の方法をとることで、jemalloc が用意する独自の関数群が利用できる。特に、jemalloc に対して様々な状態取得、動作モード指示が可能なmallctl() が使えるようになることが大変大きなメリットとなる。

ただしこの組み込み方法をとった場合、移植性を損なわないための工夫が必要である。具体的には非jemalloc 環境に備えて、jemalloc 独自関数を#ifde で囲うなどするとよい。

1. 2. の方法には当然デメリットもある。これらの方法でjemalloc が適用されるのはプロセス全域である。プロファイル、リークチェック目的の場合、プロセスの規模が大きいと範囲が広くなりすぎてしまい、狙った部分の解析が思うようにできないかもしれない。

それに対して 3. の手法を用いることで、きめ細やかな適用が可能となる。

jemalloc に含まれるmalloc() がhoge_malloc() (hoge 部分は自由に指定可能)としてライブラリ化される。これにより、実装者が意図的にjemalloc とglibc を切り替えることが可能となる。具体的には、自分の実装した部分だけ、jemalloc をリンクする、もしくは特定のモジュールのメモリ使用についてのみプロファイルを行う、などが可能となる。

以下では、それぞれの組み込み方法を具体的に簡単なコード例で紹介する。

LD_PRELOAD 環境変数を用いた組み込み

leak_memory.c というソースコードを作成し、leak_memory というアプリケーションをビルドする。

なおここで使うjemalloc は次のようにビルドした。

$ ./configure --enable-prof --enable-debug
$ make

leak_memory 実行時にLD_PRELOAD 環境変数でjemalloc をロードする。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void
leak_memory(void){
    char *ptr1, *ptr2;

    ptr1 = (char *)malloc(32);
    ptr2 = (char *)malloc(1024);

    (void)ptr1; // For warnings
    (void)ptr2; // For warnings

    return;
}

int
main(void)
{
    printf("#### Leak Memory test ####\n");
    leak_memory();
    return 0;
}

ビルドは普通に行う。jemalloc という文字はここまでどこにも現れていない。

$ g++ -g -Wall -Wextra  -c leak_memory.c
$ g++ -o leak_memory   leak_memory.o

次に実行する。ここでjemalloc が初めて出現する。

$ MALLOC_CONF="prof_leak:true,lg_prof_sample:1" LD_PRELOAD=./lib/libjemalloc.so ./leak_memory

結果、jemalloc によりメモリリークが検出されている。

#### Leak Memory test ####
<jemalloc>: Leak summary: 1056 bytes, 2 objects, 2 contexts
<jemalloc>: Run pprof on "jeprof.7693.0.f.heap" for leak detail

直接リンクによる組み込み

ソースコードは先ほど同様だが、main の終わりでjemalloc 独自のmalloc_stats_print()関数を読んでみる。ただし移植性を保持するためマクロ(USE_JEMALLOC)で保護する。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef USE_JEMALLOC
#include <jemalloc/jemalloc.h>
#endif /* USE_JEMALLOC */


void
leak_memory(void){
    char *ptr1, *ptr2;

    ptr1 = (char *)malloc(32);
    ptr2 = (char *)malloc(1024);

    (void)ptr1; // For warnings
    (void)ptr2; // For warnings

    return;
}

int
main(void)
{
    printf("#### Leak Memory test ####\n");
    leak_memory();


#ifdef USE_JEMALLOC
    malloc_stats_print(NULL, NULL, NULL);
#endif /* USE_JEMALLOC */

    return 0;
}

今回はMakefile も書いてみる。具体的には引数にJEMALLOC=yes が付与された時のみjemalloc をリンクするようにしている。

CC      = g++
LINK    = g++

ifeq ($(JEMALLOC),yes)
  CFLAGS  = -g -Wall -Wextra -I./include -DUSE_JEMALLOC
  LDLIBS  = -Wl,-rpath,./lib -L./lib -ljemalloc
  malloc_conf = "prof_leak:true,lg_prof_sample:1"
else
  CFLAGS  = -g -Wall -Wextra
  LDLIBS  =
endif

objs = leak_memory.o
exe  = leak_memory


all:$(exe) $(exe_j) run

$(exe):$(objs)
    $(LINK) -o $@ $< $(LDLIBS)

run:
    @echo "Run leak_memory by jemalloc"
    MALLOC_CONF=$(malloc_conf)  ./$(exe)

.c.o:
    $(CC) $(CFLAGS) $(CDFLAGS) -c $<

実行はjemalloc を使うパターンと使わないパターンを行う。

まずはjemalloc を使わないパターン。

$ make
g++ -g -Wall -Wextra  -c leak_memory.c
g++ -o leak_memory leak_memory.o 
Run leak_memory by jemalloc
MALLOC_CONF=  ./leak_memory
#### Leak Memory test ####

jemalloc 特有のリークチェックや今回追加したmalloc_stats_print() の出力は見られない。

次にjemalloc を使う場合。

$ make JEMALLOC=yes                         (git)-[master] - --05/31/14 20:39--
g++ -g -Wall -Wextra -I./include -DUSE_JEMALLOC  -c leak_memory.c
g++ -o leak_memory leak_memory.o -Wl,-rpath,./lib -L./lib -ljemalloc
Run leak_memory by jemalloc
MALLOC_CONF="prof_leak:true,lg_prof_sample:1"  ./leak_memory
#### Leak Memory test ####
___ Begin jemalloc statistics ___
Version: 3.6.0-29-gb4d62cd61b46130b7947c3a427a2b007e7fa0eb8
Assertions enabled
Run-time option settings:
  opt.abort: true
  opt.lg_chunk: 22
  opt.dss: "secondary"
  opt.narenas: 8
  opt.lg_dirty_mult: 3
  opt.stats_print: false
  opt.junk: true
  opt.quarantine: 0
  opt.redzone: false
  opt.zero: false
  opt.tcache: true
  opt.lg_tcache_max: 15
  opt.prof: true
  opt.prof_prefix: "jeprof"
  opt.prof_active: true
  opt.lg_prof_sample: 1
  opt.prof_accum: false
  opt.lg_prof_interval: -1
  opt.prof_gdump: false
  opt.prof_final: true
  opt.prof_leak: true
CPUs: 2
Arenas: 8
Pointer size: 8
Quantum size: 16
Page size: 4096
Min active:dirty page ratio per arena: 8:1
Maximum thread-cached size class: 32768
Average profile sample interval: 2 (2^1)
Average profile dump interval: N/A
Chunk size: 4194304 (2^22)
Allocated: 258720, active: 262144, mapped: 8388608
Current active ceiling: 4194304
chunks: nchunks   highchunks    curchunks
              2            2            2

arenas[0]:
assigned threads: 1
dss allocation precedence: secondary
dirty pages: 64:0 active:dirty, 0 sweeps, 0 madvises, 0 purged
            allocated      nmalloc      ndalloc    nrequests
small:         217760          334            0            0
large:          40960            3            0            3
huge:               0            0            0            0
total:         258720          337            0            3
active:        262144
mapped:       4194304
bins:     bin  size regs pgs    allocated      nmalloc      ndalloc    nrequests       nfills     nflushes      newruns       reruns      curruns
[0..4]
            5    80   50   1         4000           50            0            0            1            0            1            0            1
            6    96   84   2         8064           84            0            0            1            0            1            0            1
            7   112   72   2         8064           72            0            0            1            0            1            0            1
[8..19]
           20  1024   63  16        64512           63            0            0            1            0            1            0            1
[21..23]
           24  2048   65  33       133120           65            0            0            1            0            1            0            1
[25..27]
large:   size pages      nmalloc      ndalloc    nrequests      curruns
         4096     1            2            0            2            2
[6]
        32768     8            1            0            1            1
[1008]
--- End jemalloc statistics ---
<jemalloc>: Leak summary: 1056 bytes, 2 objects, 2 contexts
<jemalloc>: Run pprof on "jeprof.8836.0.f.heap" for leak detail

jemalloc のリークチェックと、malloc_stats_print() の出力(長い。。)が得られた。

--with-jemalloc-prefix= を使った組み込み

事前にjemalloc を--with-jemalloc-prefix= 付きでビルドする。

$ ./configure --with-jemalloc-prefix=hoge_ --enable-prof
$ make

これでhoge_malloc() というシンボル名になったjemalloc ができる。

これを次のようなコードに適用する。ayac_malloc() はメモリリーク等を調べたい箇所、other_malloc() はまあ大丈夫だろう。という箇所。 (今回はother_malloc()もわざとリークされている)

USE_JEMALLOC の時はayac_malloc() だけjemalloc 内のhoge_malloc() に置き換えている。これにより、調査範囲が狭まるはずだ。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef USE_JEMALLOC
  #include <jemalloc/jemalloc.h>
  #define ayac_malloc(sz) hoge_malloc(sz)
#else
  #define ayac_malloc(sz) malloc(sz)
#endif /* USE_JEMALLOC */

#define other_malloc(sz) malloc(sz)

void
leak_memory(void){
    char *ptr1, *ptr2;

    ptr1 = (char *)ayac_malloc(32);
    ptr2 = (char *)ayac_malloc(1024);

    (void)ptr1; // For warnings
    (void)ptr2; // For warnings

    return;
}

void
other_func(void){
    char *ptr;
    ptr = (char *)other_malloc(32);
    (void)ptr; // For warnings
    return ;
}

int
main(void)
{
    printf("#### Leak Memory test ####\n");
    leak_memory();
    other_func();
#ifdef USE_JEMALLOC
    hoge_malloc_stats_print(NULL, NULL, NULL);
#endif /* USE_JEMALLOC */
    return 0;
}

Makefile は先ほどと一緒だが1点だけ、24行目が異なる。

    HOGE_MALLOC_CONF=$(malloc_conf)  ./$(exe)

prefix はオプションを渡す環境変数にまで及んでいる点に注意。

これを実行する。

$ make JEMALLOC=yes

途中省略

### Leak Memory test ####
___ Begin jemalloc statistics ___
Version: 3.6.0-29-gb4d62cd61b46130b7947c3a427a2b007e7fa0eb8
Assertions enabled
Run-time option settings:
  opt.abort: true
  opt.lg_chunk: 22

途中省略

--- End jemalloc statistics ---
<jemalloc>: Leak summary: 1056 bytes, 2 objects, 2 contexts
<jemalloc>: Run pprof on "jeprof.27137.0.f.heap" for leak detail

見事にhoge_malloc() に置き換えた箇所のリークだけ検出されている。(1024byte + 32byte で1056byteが最後に指摘されている。 )

もちろん先ほどと同様、makeのみでビルドした場合、jemalloc は一切の関与を行わない。

終わりに

jemalloc をビルドし、いくつかの方法でアプリケーションに組み込んだ。

組み込み方法には一長一短があり、目的と対象によって使い分けると良いだろう。

次回はjemalloc がもつ様々なオプションをより詳細に調査したい。

Linuxプログラミングインタフェース

Linuxプログラミングインタフェース

省メモリプログラミング―メモリ制限のあるシステムのためのソフトウェアパターン集 (Software patterns series)

省メモリプログラミング―メモリ制限のあるシステムのためのソフトウェアパターン集 (Software patterns series)

  • 作者: ジェイムズノーブル,チャールズウィアー,James Noble,Charles Weir,安藤慶一
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2002/06/20
  • メディア: 単行本
  • 購入: 1人 クリック: 100回
  • この商品を含むブログ (35件) を見る

参考

Getting Started · jemalloc/jemalloc Wiki · GitHub

jemalloc について調べたのでまとめた

※この記事は3回シリーズのうちの一つ

jemalloc について調べたのでまとめた - zonomasaの日記

続 jemalloc について調べたのでまとめた(ビルドと組み込み方法) - zonomasaの日記

jemalloc の解析機能 - zonomasaの日記

photo by mutednarayan

jemalloc とは

jemalloc は、標準ライブラリで定義されているmalloc, free 等のメモリアロケーション APIの実装である。

jemalloc : 公式ページ

jemalloc は2005年より、Jason Evans によって開発されており、SMPでのスケーラビリティのためにFreeBSD のlibcに取り込ま標準アロケータとなっている。

その他にも、Facebook の内部や、KVS のRedisfluentd などにも取り込まれている。

具体的には、malloc(), calloc(), realloc(), posix_memaligne(), free() の実装を提供する。この他に、次に述べる特徴を持っている。

jemalloc の特徴

jemalloc の特徴は以下の3点である。

  • マルチコア環境でのマルチスレッドプログラムのスケーラビリティを改善する
  • メモリ領域で発生するフラグメンテーション(無駄な領域)を減らす
  • メモリの使用にまつわる種々の問題を解決するための検査機構、ツールを提供する

マルチスレッドプログラムのスケーラビリティ

マルチスレッドプログラムでのスケーラビリティ改善について、jemallocでは以下のような施策を行っている。

  • arena(1セットのメモリ領域)を複数保持する
  • スレッドごとにThread Local Storage を用いてarenaとのヒモ付を行う
  • arena、もしくはarenaの中のサイズクラスごとにLock を持つことでスレッド間の排他を削減する

この効果については、MySQLベンチマークGlibc mallocと、GoogleのTcmalloc、そしてjemalloc を比較した記事が参考になる。

MySQL performance: Impact of memory allocators (Part 2)

この記事では、おおよそ次のようなことが述べられている。

  • glibc mallocとjemalloc、tcmallocをMySQLベンチマークで比較
    • コアとスレッドを変化させてパフォーマンス計測
  • (スレッドの増加はは64でほぼサチる
  • jemallocとtcmallocはコアの増加でトランザクション数/秒をきっちりスケール
  • tcmalloc とjemallocはほとんど同じ性能
  • glibc mallocは8コア以上でロック競合のため性能が劣化している
  • 結論:MySQLを使うサーバのコアが8よりも大きい場合はglibc 以外のアロケータを試す価値がある

jemalloc の作者であるJason Evans はglibc mallocは 6-8cpu で性能が劣化する(※)と過去に言っているが、上記実験結果はその傾向が現れているとも読める。

※:

フラグメンテーションを削減する

jemalloc は、小さいサイズの割り当て要求のために、複数のsize class というものを用意している。割り当て要求は最も近いsize classにround up され、実際のメモリ領域が割り当てられる。この時、領域のフラグメンテーションを削減するために、roud up するサイズの最大値を要求サイズの25%以下になるようにしている。

具体的にはsize class は以下のようになっている。 8, 16, 32, ..(この間16づつ増加)... ,128, 160, 192, 224, 256, 320, ...

つまりサイズが増えるに従い、クラス間の増分を増やしている。例えば257byte の割り当て要求が来た場合、320byte にroud upされる。この時に無駄になる領域は63byte となり、これは257byte に対して約24.5 %となり、前述の25%以下に収まっていることがわかる。

しかし、glibc malloc も同様にsize classを持っており、512byte までは8byte 刻みのclass が設定されているため、一概にjemalloc が有利とは言えない(むしろglibc malloc のほうが有利と解釈できる)

ただし、jemalloc は最小で8byte の割り当てができる点が大きい。glibc mallocは16byteである。

以下の記事はmruby でのメモリ使用量最適化について書かれており、Ruby のオブジェクトを管理する基本型VALUE が6byteであるため、glibc malloc では10byte の無駄が生じるが、jemlalloc ではこれが2byte となるため、全体的にメモリ使用量が減っていると考察している。

人間とウェブの未来 - mod_mrubyのメモリ問題をvalgrindで調査の上jemallocで改善

jemalloc の検査機構、ツール、便利関数

jemalloc では次のようなエラー検知が可能である。

  • メモリリークの検出
  • double free,アラインメント境界違反 の検出
  • オーバーフロー(Valgrindと連携して検出)

その他にも様々な機能がある。

  • malloc(), free() の際に0ではない無効な値(0xa5)で領域を埋める。
  • 使用状況・内部状況をHuman readable な形式で出力(プロセス終了時、API呼び出し時)
  • 内部パラメータ変更によるチューニング手段の提供(数十のパラメータ)

メモリリークについては、プロセス終了時にサマリを提供してくれる他に、GoogleのTcmalloc の成果であるpprof というツールに対応しており、より詳細な解析を可能としている。

https://github.com/jemalloc/jemalloc/wiki/images/w.png pprofの出力 (引用元:Github

終わりに

昨今、様々なミドルウェアで使用されるjemalloc について調べた。今後、実際の使い方などについても調べて公開していきたいと思う。

省メモリプログラミング―メモリ制限のあるシステムのためのソフトウェアパターン集 (Software patterns series)

省メモリプログラミング―メモリ制限のあるシステムのためのソフトウェアパターン集 (Software patterns series)

  • 作者: ジェイムズノーブル,チャールズウィアー,James Noble,Charles Weir,安藤慶一
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2002/06/20
  • メディア: 単行本
  • 購入: 1人 クリック: 100回
  • この商品を含むブログ (35件) を見る

参考リンク

Android 開発ではデフォルトのiconを活用しよう

photo by ichibod

はじめに

Androidアプリケーションを開発する際に困るのはアイコンを始めとするデザイン。

そんなデザインについては、Google が凝ったデザインではなくコンテンツで勝負しましょう、と呼びかけています。

開発者は必見? GoogleがAndroidアプリのUXアンチパターン動画を公開 – すまほん!!

スマートフォンアプリで必要となるアイコンも、数多くのパターンがAndroid SDK に収められています。

標準を使うことはビューと使用感の統一につながります。独自にアイコンを用意する手間も省けますね。

標準のアイコンってどんなのがあるの?

標準のアイコンはSDKのフォルダ内に格納されています。

例えば、MacOSX のAndroidStudio 付属のSDKの場合、以下のパスになります。※SDKバージョンは適宜読み替えてください。

/Applications/Android Studio.app/sdk/platforms/android-19/data/res/drawable-hdpi

ここをFinderで開くとアイコンを始めとするdrawable が表示されます。例えばメニューアイコンに絞りたい場合、"ic_menu" で検索をします。

f:id:zonomasa:20140511112328p:plain

アイコンを使う

適切なアイコンを見つけたらあとはコード中から呼び出しましょう。

        android:background="@android:drawable/ic_menu_myplaces"

おわりに

Android開発で使える標準のアイコンの閲覧と使用方法を説明しました。

Android Studio で開発するアプリケーションにAdMobを導入する

photo by eldeeem

はじめに

Android Studio で開発するアプリケーションにAdMobを導入します。

AdMobはGoogleが提供する広告バナー導入のためのライブラリ・サービスです。

公式ドキュメントEclipse向けに記述されているため、AndroidStudio向けの作業を記します。

AdMobへの登録

AdMobへの登録自体は開発環境に依存しませんので割愛します。このあたりのページを参照してください。

AndroidStudio にAdMobライブラリを追加する

AndroidStudioのメニューから作業をします。

Tools->Android->SDK Manager でSDK管理画面を起動します。

Extras にあるGoogle Play Services, Google Play Repository をインストールします。

f:id:zonomasa:20140429100849p:plain

アプリケーションにAdMobライブラリを追加する。

アプリケーションにAdMobライブラリを追加します。

AndroidManifest

        <meta-data android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version"/>

        <activity android:name="com.google.android.gms.ads.AdActivity"
            android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>

appの下にあるBuild.gradle

dependencies {
    compile 'com.google.android.gms:play-services:4.3.23'
}

Build.gradle に記載するバージョンは最新のものを使う場合、AndroidStudio がポップアップで教えてくれるので、それに従えば良いです。

f:id:zonomasa:20140429101654p:plain

Activity から呼び出す

Activityからの呼び出しは従来通り行えばよいです。公式ドキュメントに従えば問題ないでしょう。

終わりに

AndroidStudioでAdMobを利用する際の導入方法について説明しました。

Smartphone Ads iPhone・Androidアプリへの広告の実装と管理テクニック

Smartphone Ads iPhone・Androidアプリへの広告の実装と管理テクニック