(57)【要約】  【課題】既存のアプリケーションを変更することなく、オブジェクト・サイズの無駄を自動的に削減できるシステムを提供すること。  【解決手段】  この発明のシステムは、初期化が終わり更新が少なくなると予想できるコレクション・オブジェクトを定期的に抽出し、内部データ構造の利用率を調べ、利用率が低い場合は、実行時システムが内部データ構造のキャパシティを自動的に縮小する。このとき、自動的に縮小することで、アプリケーション開発者の技量に依存せずに無駄なメモリ使用を削減できる。この発明の別の側面によれば、縮小処理をＧＣ時に行うことで、効率よく実装する。すなわち、ＧＣによるオブジェクト移動処理では元々オブジェクト参照を修正が必要なので、キャパシティ縮小も同時に行えば、縮小後のキャパシティにあわせてデータの再配置するためにオブジェクト参照を修正する処理が、追加オーバーヘッドなしで実現できる。【選択図】  図３
2014225077.tif 000002
【特許請求の範囲】
【請求項１】
コンピュータの処理により、コンピュータのメモリを管理する方法であって、
内部配列を含むコレクション・オブジェクトを生成するステップと、
間欠的に前記コレクション・オブジェクトの利用率を調べるステップと、
前記利用率が所定の利用率以下であることに応答して、前記コレクション・オブジェクトのうち、初期化が終わり更新が少なくなると予想できるコレクション・オブジェクトに対してのみ、内部配列のサイズを縮小するステップを有する、
方法。
【請求項２】
前記コンピュータは、プログラム言語実行環境を実装するものである、請求項１に記載の方法。
【請求項３】
前記プログラム言語実行環境がＪＶＭである、請求項２に記載の方法。
【請求項４】
前記内部配列のサイズを縮小するステップは、ＧＣ時に実行される、請求項３に記載の方法。
【請求項５】
前記初期化が終わり更新が少なくなると予想できるコレクション・オブジェクトであるとの判断は、以下の(a)、(b)、(c)あるいは(d)どれかに基づき行われる、請求項４に記載の方法。
(a) ＪＶＭが世代別GCを用いている場合、コレクション・オブジェクトが第２世代領域に移動された場合、
(b) Mark and sweep GCを用いている場合、compactionを2回以上生き延びたオブジェクトの場合、
(c) get()メソッドなどによって、データの挿入・削除以外の操作が一定回数以上実行されたオブジェクトの場合、
(d) 自動縮小対象を、まだ一度も自動縮小していないコレクション・オブジェクト。
【請求項６】
前記コレクション・オブジェクトが、HashMapまたはArrayListである、請求項５に記載の方法。
【請求項７】
コンピュータの処理により、コンピュータのメモリを管理するプログラムであって、
前記コンピュータに、
内部配列を含むコレクション・オブジェクトを生成するステップと、
間欠的に前記コレクション・オブジェクトの利用率を調べるステップと、
前記利用率が所定の利用率以下であることに応答して、前記コレクション・オブジェクトのうち、初期化が終わり更新が少なくなると予想できるコレクション・オブジェクトに対してのみ、内部配列のサイズを縮小するステップを実行させる、
プログラム。
【請求項８】
前記コンピュータは、プログラム言語実行環境を実装するものである、請求項７に記載のプログラム。
【請求項９】
前記プログラム言語実行環境がＪＶＭである、請求項８に記載のプログラム。
【請求項１０】
前記内部配列のサイズを縮小するステップは、ＧＣ時に実行される、請求項９に記載のプログラム。
【請求項１１】
前記初期化が終わり更新が少なくなると予想できるコレクション・オブジェクトであるとの判断は、以下の(a)、(b)、(c)あるいは(d)どれかに基づき行われる、請求項１０に記載のプログラム。
(a) ＪＶＭが世代別GCを用いている場合、コレクション・オブジェクトが第２世代領域に移動された場合、
(b) Mark and sweep GCを用いている場合、compactionを2回以上生き延びたオブジェクトの場合、
(c) get()メソッドなどによって、データの挿入・削除以外の操作が一定回数以上実行されたオブジェクトの場合、
(d) 自動縮小対象を、まだ一度も自動縮小していないコレクション・オブジェクト。
【請求項１２】
前記コレクション・オブジェクトが、HashMapまたはArrayListである、請求項１１に記載のプログラム。
【請求項１３】
請求項１乃至請求項６のうちの方法１つの請求項を実行するためのコンピュータ・システム。
【発明の詳細な説明】
【技術分野】
【０００１】
この発明は、コンピュータにおいてオブジェクトを管理するための技法に関し、より詳しくは、必要に応じてオブジェクトのサイズを縮小するための技法に関する。
【背景技術】
【０００２】
従来より、Java(R)などの処理環境において、ハッシュ表や集合型、コレクション・オブジェクトなどの抽象データ型が標準ＡＰＩに含まれており、これらを用いると、実行時でないと総量が分からないデータも簡単に扱うことができる。
【０００３】
これらのＡＰＩの実装では、内部で配列を使う場合がある。例えば、一般的なハッシュ表の実装法の１つに、オープン・ハッシュ表がある。この実装では、ハッシュ表はバケット(bucket)配列（もしくはバケット表）と呼ばれる配列と、バケット配列の各要素から指されるリンクリストで構成される。キーとして与えられた値から適当なハッシュ関数を用いてバケット表のインデックスを計算し、対応する要素に繋がっているリンクリストに、キーと値のペアを格納する。
【０００４】
バケット配列のサイズはライブラリが適当に決めれば良いのであるが、ハッシュ表に含まれる要素数に対して小さすぎるとリンクリストが長くなって実行速度が低下する恐れがある。逆に、大きすぎると、リンクリストが繋がっていない要素が多くなって、メモリが無駄になる。なお、バケット配列については、Alfred V. Aho, Jeffrey D. Ullman, John E. Hopcroft, "Data Structures and Algorithms" (Addison-Wesley Series in Computer Science and Information Pr), 1983などの文献を参照されたい。
【０００５】
そのような内部配列を使用する場合、適当な初期サイズの配列を用意しておき、データが増えて配列が一杯になったら、より大きな配列を作成してデータをコピーする実装が一般的である。しかし、挿入されるデータ数によっては、配列が無駄に大きい場合がある。データが挿入されなかったり、１〜３個程度のデータしか挿入されなかった場合は、初期サイズの配列でも大きすぎてメモリが無駄になる。また、配列を大きく拡張したあとで挿入されたデータが少ないために、利用率が１／３以下にとどまるものも少なくない。
【０００６】
従来技術として、特開２００９−６４２１７号公報は、重複した文字列データをＧＣ時に一つにまとめる、ストリングＧＣ技法を開示するものであるが、コレクション・オブジェクトを個別に縮小することには適用できない。
【０００７】
http://www.gnu.org/software/guile/manual/html_node/Hash-Table-Reference.htmlには、コレクション・オブジェクトにデータの挿入および削除する時に、必要に応じて内部データ構造を拡大および縮小する処理は、既存のプログラムでも実装されている。しかし、起動時に設定ファイルなどを読み込んで、その内容をハッシュ表などに保持し、その後は参照のみ行う場合、データ削除時に縮小する方法は効果がない。
【０００８】
http://blog.gmane.org/gmane.lisp.scheme.mit-scheme.devel/month=20110901にある、Scheme開発者のメーリングリストでは、ＧＣ時にハッシュ表をリハッシュ(rehash)してバケット配列を縮小することが議論されているが、そこにあるのは、ＧＣ中にハッシュ表オブジェクトのリハッシュ関数を呼ぶ事の是非についての議論だけである。ＧＣがハッシュ表オブジェクトの内容を直接書き換えることで、効率的に実装できることについては言及されていない。また、ハッシュ表以外のデータ構造（JavaのArrayListなど）についての議論はない。
【０００９】
http://msdn.microsoft.com/ja-jp/library/system.collections.arraylist%28v=vs.80%29.aspxなどに記述がある、.Net FrameworkのArrayListクラスは、内部データ構造のキャパシティを指定するTrimToSizeメソッドを持つ。しかし、HashTableクラスにはキャパシティを指定するAPIを持たない。そして、実行時システムに組み込まないと、無駄なメモリ使用を削減できるかどうかがAPI仕様に依存する。
【先行技術文献】
【特許文献】
【００１０】
【特許文献１】特開２００９−６４２１７号公報
【非特許文献】
【００１１】
【非特許文献１】http://www.gnu.org/software/guile/manual/html_node/Hash-Table-Reference.html
【非特許文献２】http://blog.gmane.org/gmane.lisp.scheme.mit-scheme.devel/month=20110901
【非特許文献３】http://msdn.microsoft.com/ja-jp/library/system.collections.arraylist%28v=vs.80%29.aspx
【発明の概要】
【発明が解決しようとする課題】
【００１２】
従って、この発明の目的は、既存のアプリケーションを変更することなく、オブジェクト・サイズの無駄を自動的に削減できるシステムを提供することにある。
【課題を解決するための手段】
【００１３】
この発明は、上記課題を解決するものであって、初期化によるデータ挿入が終わっても利用率の低いコレクション・オブジェクトを、プログラム言語実行環境が自動的にキャパシティを縮小するシステムを実現する。ここでの好適なプログラム言語実行環境は、ＪＶＭである。
【００１４】
すなわち、この発明のシステムは、初期化が終わり更新が少なくなると予想できるコレクション・オブジェクトを定期的に抽出し、内部データ構造の利用率を調べ、利用率が低い場合は、実行時システムが内部データ構造のキャパシティを自動的に縮小する。このとき、自動的に縮小することで、アプリケーション開発者の技量に依存せずに無駄なメモリ使用を削減できる。
【００１５】
たとえば、クラウド環境では、一つのアプリケーションが無駄にメモリを使用すると、他の仮想マシン上で動くアプリケーションも含め、同じ物理マシン上で実行される全てのアプリケーションの使用可能な物理メモリ量が減少し、マシンの利用効率が低下する。よって、自動的に縮小する処理は効果が大きい。
【００１６】
また、キャパシティの自動縮小後にデータが追加されて内部配列が拡張されると、自動縮小処理は不要なオーバーヘッドとなってしまう。このようなことが発生する可能性を低減するために、初期化が終わり更新が少なくなると予想されるコレクションだけを自動縮小する。
【００１７】
好適には、（クラスライブラリを含む）実行時システムが実装を知っているコレクションオブジェクトをキャパシティ自動縮小の対象とし、縮小処理を実行時システムに組み込むことで、クラスライブラリのAPI仕様に依存せず、効率のよい実装を可能にする。
【００１８】
初期化が終わり更新が少なくなると予想できるかどうかの判断は、たとえば以下の方法を用いる。
−  プログラム言語実行環境、例えばＪＶＭが世代別ＧＣを用いている場合、コレクション・オブジェクトがtenured領域に移動された場合。
−  Mark and sweep GCを用いている場合、コンパクション(compaction)を2回以上生き延びたオブジェクトの場合。
−  あるコレクション・オブジェクトに対し、get()メソッドなど、データの挿入・削除以外の操作が一定回数以上実行された場合。
−  コレクションに含まれるデータ数の変動幅が、一定期間充分小さく（たとえば10％以内）なった場合。
−  好適には、自動縮小対象を、まだ一度も自動縮小していないコレクション・オブジェクトに限定する。
【００１９】
この発明の別の側面によれば、縮小処理をＧＣ時に行うことで、効率よく実装する。すなわち、ＧＣによるオブジェクト移動処理では元々オブジェクト参照を修正が必要なので、キャパシティ縮小も同時に行えば、縮小後のキャパシティにあわせてデータの再配置するためにオブジェクト参照を修正する処理が、追加オーバーヘッドなしで実現できる。
【発明の効果】
【００２０】
この発明によれば、ほとんど追加コストなく、オブジェクト・サイズの無駄を自動的に削減できるシステムが提供される。このようなシステムは特に、クラウド環境でメモリ利用効率を向上させる効果が大きい。
【図面の簡単な説明】
【００２１】
【図１】本発明を実施するためのハードウェアの一例のブロック図である。
【図２】本発明を実施するためのソフトウェアの階層を示す図である。
【図３】ＧＣによるHashMapオブジェクト移動処理のフローチャートを示す図である。
【図４】HashMap内のすべてのエントリを移動するフローチャートを示す図である。
【図５】ＧＣによるArrayListオブジェクト移動処理のフローチャートを示す図である。
【発明を実施するための形態】
【００２２】
以下、図面に従って、本発明の実施例を説明する。これらの実施例は、本発明の好適な態様を説明するためのものであり、発明の範囲をここで示すものに限定する意図はないことを理解されたい。また、以下の図を通して、特に断わらない限り、同一符号は、同一の対象を指すものとする。
【００２３】
図１を参照すると、本発明の一実施例に係るシステム構成及び処理を実現するためのコンピュータ・ハードウェアのブロック図が示されている。図１において、システム・バス１０２には、ＣＰＵ１０４と、主記憶（ＲＡＭ）１０６と、ハードディスク・ドライブ（ＨＤＤ）１０８と、キーボード１１０と、マウス１１２と、ディスプレイ１１４が接続されている。ＣＰＵ１０４は、好適には、３２ビットまたは６４ビットのアーキテクチャに基づくものであり、例えば、インテル社のCore(商標) i3、Core(商標) i5、Core(商標) i7、Xeon(R)、AMD社のAthlon(商標)、Phenom(商標)、Sempron(商標)などを使用することができる。主記憶１０６は、好適には、８ＧＢ以上の容量、より好ましくは、１６ＧＢ以上の容量をもつものである。
【００２４】
ハードディスク・ドライブ１０８には、オペレーティング・システム（ＯＳ）２０２（図２）が、格納されている。オペレーティング・システムは、Linux（商標）、マイクロソフト社のWindows(商標) 7、Windows 8(商標)、Windows(商標)2003サーバ、アップルコンピュータのMac OS(商標)などの、ＣＰＵ１０４に適合する任意のものでよい。
【００２５】
ハードディスク・ドライブ１０８にはまた、Apacheなどの、Ｗｅｂサーバとしてシステムを動作させるためのプログラムが保存され、システムの起動時に、主記憶１０６にロードされる。
【００２６】
ハードディスク・ドライブ１０８にはさらに、Java(R)仮想マシン（ＪＶＭ）２０４（図２）を実現するためのJava(R) Runtime Environmentプログラムが保存され、システムの起動時に、主記憶１０６にロードされる。ＪＶＭ２０４には、本発明の機能が実装されている。
【００２７】
ハードディスク・ドライブ１０８にはさらに、アプリケーション・プログラムのバイトコード２０６（図２）が保存されている。
【００２８】
キーボード１１０及びマウス１１２は、オペレーティング・システムが提供するグラフィック・ユーザ・インターフェースに従い、ディスプレイ１１４に表示されたアイコン、タスクバー、テキストボックスなどのグラフィック・オブジェクトを操作するために使用される。
【００２９】
ディスプレイ１１４は、これには限定されないが、好適には、１０２４×７６８以上の解像度をもち、３２ビットtrue colorのＬＣＤモニタである。ディスプレイ１１４は例えば、ＪＶＭ上で実行されるアプリケーション・プログラムによる動作の結果を表示するために使用される。
【００３０】
通信インターフェース１１６は、好適には、イーサネット(R)プロトコルにより、ネットワークと接続されている。通信インターフェース１１６は、クライアント・コンピュータ（図示しない）からApacheが提供する機能により、ＴＣＰ／ＩＰなどの通信プロトコルに従い、処理リクエストを受け取り、あるいは処理結果を、クライアント・コンピュータ（図示しない）に返す。
【００３１】
アプリケーション・プログラム２０８は、Java(R)バイトコードから構成され、ＪＶＭ２０４上で動作する。ＪＶＭ２０４は、本発明のオブジェクト自動縮小機能を備えた、カスタマイズされたＪＶＭである。
【００３２】
ＪＶＭ２０４は、アプリケーション・プログラム２０８のために、主記憶１０８上にヒープ領域を用意する。アプリケーション・プログラム２０８は、動作中にヒープ領域上にメモリ領域を獲得して、そこに、生成したオブジェクトを割り付ける。
【００３３】
ＪＶＭ２０４は、世代別(generational)ヒープ領域をサポートするものであってもよい。世代別ヒープ領域である場合、新しいオブジェクトを割り付けるための、少なくとも１つの第１世代の(nursery)ヒープ領域と、少なくとも１つの第２世代の(tenured)ヒープ領域からなり、ＪＶＭ２０４は、第１世代のヒープ領域が一杯になったとき、第１世代のヒープ領域でガベージ・コレクション（ＧＣ）を行い、第１世代のヒープ領域のＧＣを複数回生き残ったオブジェクトを第１世代のヒープ領域から、第２世代のヒープ領域に移動する。結果的に、第２世代のヒープ領域には、しばらく生き残っているオブジェクトが集まる。また、第２世代のヒープ領域が一杯になると、ＪＶＭ２０４はヒープ領域全体のＧＣを行う。
【００３４】
ＪＶＭ２０４は、非世代別(non-generational)ヒープ領域をサポートするものであってもよい。一方、非世代別ヒープ領域である場合、ヒープ領域は全て、第１世代のヒープ領域として扱われる。本発明は、世代別ヒープ領域と非世代別ヒープ領域の両方に適用可能である。
【００３５】
さらには、ＪＶＭ２０４は、マーク・アンド・スイープ(mark and sweep)で、ＧＣを実装するものであってもよい。
【００３６】
ＪＶＭ２０４は、間欠的に、内部配列を含むコレクション・オブジェクトの利用率を調べ、その利用率が所定の利用率以下であることに応答して、前記コレクション・オブジェクトのうち、初期化が終わり更新が少なくなると予想できるコレクション・オブジェクトに対してのみ、内部配列のサイズを縮小する。
【００３７】
このとき例えば、利用率は次のようにして調べられる。すなわち、Java(R)クラスライブラリなど汎用的なハッシュ表の実装では、要素数を返すAPIが用意されていたり、要素数が増えたときにrehashを行う必要があるので、内部変数として要素数を保持している。そこで、バケット配列のサイズから求める「バケット配列のサイズに対して適切な要素数」と、内部変数に保持している要素数の比から利用率を求める。
【００３８】
ＪＶＭ２０４は、好適には、ＧＣに応答して、前記コレクション・オブジェクトのうち、初期化が終わり更新が少なくなると予想できるコレクション・オブジェクトに対してのみ、内部配列のサイズを縮小する。ＪＶＭ２０４は、下記の条件に従い、コレクション・オブジェクトが初期化が終わり更新が少なくなると予想する。
−  プログラム言語実行環境、例えばＪＶＭが世代別ＧＣを用いている場合、コレクション・オブジェクトが第２世代の領域に移動された場合。
−  Mark and sweep GCを用いている場合、コンパクション(compaction)を2回以上生き延びたオブジェクトの場合。
−  あるコレクション・オブジェクトに対し、get()メソッドなど、データの挿入・削除以外の操作が一定回数以上実行された場合。
−  コレクションに含まれるデータ数の変動幅が、一定期間充分小さく（たとえば10％以内）なった場合。
−  好適には、自動縮小対象を、まだ一度も自動縮小していないコレクション・オブジェクトに限定する。
【００３９】
ここで、Mark and sweep GCでは、GCを繰り返すうちにヒープ領域が断片化する傾向にある。そのため、いわゆるデフラグのような処理を行って断片化を解消する処理を、GCの分野ではcompactionと呼ぶ。compactionにより断片化を解消する処理については、http://www.ibm.com/developerworks/library/j-ibmjava2/のoptthruputの章などを参照されたい。また、本発明のために、オブジェクトに「過去にcompactionを生き延びたかどうか」のフラグをつけられる。ＧＣがcompactionを行う際に、まだ生きているコレクション・オブジェクトを見つけたら、このフラグが立っているかどうかを調べる。このフラグが立っていれば、過去に1回以上compactionを生き延び、今回のcompactionも生き延びたので、2回以上生き延びたことが分かる。
【００４０】
また、この発明によれば、各コレクション・オブジェクトに、get()メソッド（その他、値を返す機能をもつ、size()などのメソッド）が何回呼ばれたかを記録する変数を用意して、呼び出し回数が把握される。ここでの一定回数は、数百から１０００程度が妥当である。
【００４１】
なお、発明の別の側面によれば、縮小処理をＧＣ時に行うことで、効率よく実装する。すなわち、ＧＣによるオブジェクト移動処理では元々オブジェクト参照を修正が必要なので、キャパシティ縮小も同時に行えば、縮小後のキャパシティにあわせてデータの再配置するためにオブジェクト参照を修正する処理が、追加オーバーヘッドなしで実現できる。
【００４２】
内部配列の縮小と移動を同時に行えば、移動先のメモリ領域に縮小後のサイズの内部配列を確保すればよく、縮小処理のために内部配列を別途アロケートする必要がなくなる。さらに、オブジェクトの移動は元々コストがかかる処理なので、バケット配列のインデックス計算などrehash処理のコストは、移動処理のコストと比較すると無視できる。
【００４３】
また、コレクション・オブジェクトの初期化が終わったかどうかの判断を、ＧＣが通常行う処理と同時に行えるので、自動縮小の対象となるオブジェクトを検索するための追加コストがない。
【００４４】
GCによるオブジェクト移動はオブジェクト単位で行われるので、移動と同時にオブジェクトがコレクションか否かや利用率などを調べることで、自動縮小対象のオブジェクトを追加コストなしに検索できる。また、世代別GCを用いている場合、第１世代領域から第２世代領域に移動されるオブジェクトは一定期間以上長生きしているので、そのようなコレクション・オブジェクトを自動縮小の対象とすれば、初期化が終わって更新が少なくなったと予想できるオブジェクトを、追加コストなしに検索できる。
【００４５】
Mark and sweep GCを使っている場合、compactionが行われる時にオブジェクトが移動されるので、同時に自動縮小対象のオブジェクトかどうかを検査すれば、追加コストなしに対象オブジェクトを検索できる。
【００４６】
次に、以上のようにして初期化が終わり更新が少なくなると予想できるコレクション・オブジェクトが特定できた場合の処理を、HashMapオブジェクトとArrayListオブジェクトの各々について、図３〜５のフローチャートを参照して説明する。
【００４７】
図３及び図４は、ＧＣによるHashMapオブジェクトの移動処理のフローチャートを示す図である。
【００４８】
図３のステップ３０２において、ＪＶＭ２０４は、移動先にHashMapオブジェクトのメモリを確保し、内容をコピーする。
【００４９】
ステップ３０４において、ＪＶＭ２０４は、移動先に縮小後のバケット配列のサイズで、メモリを確保する。
【００５０】
ステップ３０６において、ＪＶＭ２０４は、HashMapの内のすべてのエントリを移動して、処理を終わる。
【００５１】
図４は、図３のステップ３０６の、より詳細な処理のフローチャートを示す図である。
【００５２】
図４のステップ４０２で、ＪＶＭ２０４は、移動してないエントリがあるかどうか判断し、そうでないなら、直ちに戻る。
【００５３】
まだ移動してないエントリがあるなら、ＪＶＭ２０４は、ステップ４０４で移動元のバケット配列からエントリを取り出し、ステップ４０６で移動先にエントリのメモリを確保し、内容をコピーする。
【００５４】
次にＪＶＭ２０４は、ステップ４０８で、エントリのハッシュ値から、移動先バケット配列のインデックスを求め、ステップ４１０で移動先バケット配列の、ステップ４０８で求めたインデックスのリストに、移動先のエントリをつなげて、ステップ４０２に戻る。
【００５５】
図５は、ＧＣによるArrayListオブジェクトの移動処理であり、ステップ５０２において、ＪＶＭ２０４は、移動先にArrayListオブジェクトのメモリを確保し、内容をコピーする。
【００５６】
ステップ５０４において、ＪＶＭ２０４は、移動先に縮小後の内部配列のサイズで、メモリを確保する。
【００５７】
次にステップ５０６において、ＪＶＭ２０４は、内部配列内の有効な要素を、移動先の内部配列にコピーして、処理を終わる。
【００５８】
上記実施例では、HashMap及びArrayListの例で説明したが、本発明はこれには限定されず、ConcurrentHashMap、LinkedListなど、AbstractCollection、AbstractList、AbstractMapなどの抽象コレクション・オブジェクトのクラスを継承する、任意のオブジェクトに適用可能である。
【００５９】
以上、この発明を、Java(R)処理系における処理を例として説明してきたが、この発明はそれには限定されず、配列をもつオブジェクトを縮小する処理が可能な任意のオペレーティング・システムあるいは処理系の下で実装可能であることを理解されたい。
【符号の説明】
【００６０】
１０４  ＣＰＵ
１０６  主記憶
１０８  ハードディスク・ドライブ
２０２  オペレーティング・システム
２０４  ＪＶＭ
【図１】
2014225077.tif 000003
【図２】
2014225077.tif 000004
【図３】
2014225077.tif 000005
【図４】
2014225077.tif 000006
【図５】
2014225077.tif 000007