2011-01-03 8 views
3

、またはその他の理由オブジェクト、またはこれらの2つのシナリオは同じです:は、メモリ管理のための優れている一般的な質問

Calendar currentDateTime = Calendar.getInstance(); 
int i= foo.getSomething(currentDateTime); 
Bar bar= foo.getBar(currentDateTime); 

他のコードブロック:

int i= foo.getSomething(Calendar.getInstance()); 
Bar bar= foo.getBar(Calendar.getInstance()); 

一般的な質問をオブジェクトのインスタンスを取得し、必要なときにそのインスタンスを使用したり、必要なときにgetInstance()を毎回呼び出したりする方がよいでしょうか。 シングルトンを扱っていないにもかかわらず、単純なPOJOを作成していれば、答えは変わりますか?

答えて

0

シングルトンの場合、それほど大きな違いはありません。一時変数を使用することで、関数呼び出しのオーバーヘッドは節約されますが、何度も同じオブジェクトが返されます。

POJOを作成する場合は、コンストラクタを呼び出すか、オブジェクト作成静的メソッドを使用して新しいオブジェクトを作成します。これは、関数呼び出しのランタイムオーバーヘッドと、作成される別のオブジェクトのメモリオーバーヘッドがあることを意味します。

一般に、メソッド本体内で同じオブジェクトを何度か使用する予定がある場合は、一時変数を使用します。この方法で、私はメモリオーバーヘッドを避ける必要があるかどうかに関わらず同じことをしています。私のコードはより一貫しています。

+0

FWIW、カレンダーはシングルトンではありません。私は、あなたやOPが暗示していたものであるとは確信していませんが、同じ質問でCalendarとgetInstanceの両方を一緒に言及して考えると、 – Tom

0
  1. より多くのメモリを使用し、より少ないCPU
  2. は少ないメモリとCPUより

を使用していますあなたは、操作のために与えたいものを決定する必要があります。 アプリケーションのボトルネックは何ですか?

+0

これはなぜでしょうか?なぜなら、私たちは2で、後で使用するために値を格納するためにcurrentDateTimeにメモリを割り当てています.Calendar.getInstance()は2回、より多くのCPUを消費します。 – Chris

+0

どのように呼び出され、どのくらいの頻度でより多くのメモリを消費する可能性があります。 getInstance()を繰り返し呼び出すと、クリーンアップするためにはるかに多くのゴミが生成されます。 –

+0

私の推測では、「currentDateTime」はメソッドへの参照によって渡されるため、メモリを少なくしています。間違っていると思いますが、何が欠けていますか? – bmw0128

2

カレンダーは非常に高価なオブジェクトです(私が知っているライブラリで最も高価な日付オブジェクトの1つです)。 getInstance()の呼び出しも非常に高価です。カレンダーを使用する必要がある場合は、キャッシュすることができます。それは本当にあなたがそれを必要とする理由にかかっています。

現在の時刻を取得して保存する最も効率的な方法は、長いプリミティブを使用することです。

long currentDateTime = System.currentTimeMillis(); 

あなたが内部的にGMT時間を使用する場合は、あなたが

int currentDay = (int)(System.currentTimeMillis()/86400000); 

EDITで、当日保存することができます:のgetInstance()は比較的高価ですが、それはかなり残っている間、それは、あなたのマシン上でテストする価値があります速い。私の古い箱には〜20マイクロ秒かかる。高速のマシンでは、currentTimeMillis()は140ナノ秒かかることがあります。明確にする

Calendar.getInstance() took on average 20088 ns. java.util.GregorianCalendar[time=1294086899359 ... deleted ...] 
System.currentTimeMillis() took on average 938 ns. 1294086899377 

コード

int runs = 10000; 
long start = System.nanoTime(); 
Calendar cal = null; 
for(int i=0;i<runs;i++) 
    cal = Calendar.getInstance(); 
long time = System.nanoTime() - start; 
System.out.println("Calendar.getInstance() took on average "+time/runs+" ns. "+cal); 

long start2 = System.nanoTime(); 
long now = 0; 
for(int i=0;i<runs;i++) 
    now = System.currentTimeMillis(); 
long time2 = System.nanoTime() - start2; 
System.out.println("System.currentTimeMillis() took on average "+time2/runs+" ns. "+now); 
+1

カレンダーはどんなに高価になるでしょうか? – marcog

+1

これは、タイムゾーン、ロケール、その日/月/年/時/分/秒のint []、およびこれらの値のいずれが設定されているかを示すブール値配列を含みます。それは "各フィールドがいつ設定されたかを指定する擬似タイムスタンプ"を持っています。これはint []と最小値のフィールドです。これはミリ秒単位でキャッシュされた時間、フィールドが設定されているかどうかを示すブール値、すべてのフィールドが設定されているかどうかを表すブール値、lenientがtrueかどうかを記録する別の値、 minimalDaysInFirstWeekの別のもの、古いシリアル化されたバージョンをデコードするためのserialVersionOnStream .... –

+0

..グレゴリオ暦の長いフィールド、そしてユリウスの日付が終わった日、カットオーバ年のフィールド。グレゴリオ暦とユリウス暦の日付がどのように計算されるか、タイムゾーンオフセットのint []、フィールドの元の値のint []の3つの参照。それはそうかもしれないが、伝えるのは難しい。 ;) –

7

次の印刷、カレンダーが実際にシングルトンではありません。 Calendar.getInstance()は、呼び出すたびに新しいオブジェクトを返します。

これは、関数getSomething()およびgetBar()がfooに新しいCalendarインスタンスを格納させる副作用を持っているかどうかによって、あなたの質問に対する答えが異なることを意味します。一般的に、良いプログラミング方法は、これが当てはまらないことを指示します。

EDIT:ただし、Calendar.getInstance()を呼び出すたびに、別の日付になる可能性があります。あなたの機能が何をしているかによって、これは重要な詳細になるかもしれません。

EDIT 2:これはまた、上記のプロセスを実行する頻度によって異なります。別の答えが指摘したように、カレンダーオブジェクトをインスタンス化することは集中的になる可能性があります。あなたがそれを2回だけ行うならば、それをキャッシュするかどうかは関係ありません。これを非常に頻繁に行う場合は、アプローチを変更したり、キャッシングを行うことを検討することができます。

0

基本的に2つの異なるシナリオを検討しています。 1.カレンダーはシングルトンです。この場合、ヘルパーメソッドを呼び出してメモリ内の単一のインスタンスを取得する必要があります。 2.カレンダーはPOJOです。 getInstance()が単にコンストラクタを呼び出すと、呼び出すたびに新しいインスタンスが作成されます。そのため、後者のケースでは予期しない結果が得られる可能性があります。

しかし、最終的には、コーディングスタイルと読みやすくなっています。一部の開発者はfactory methodsを使用する方が好きで、単にコンストラクタを直接呼び出す方が好きな人もいます。私の考えでは、オブジェクトが単純なエンティティ(ビルドアップが不要)であれば、newを呼び出すことはオブジェクトを作成する最も単純な方法です。一方、ビルドアップがあり、一般的に読みやすいコードが必要な場合は、ファクトリメソッドがより好ましいです。

メモリ管理の観点からは、コンストラクタを呼び出すたびに、クラスの新しいインスタンスが取得されます。あなたはその新しいインスタンスを使うつもりですか?タイムリーにガベージコレクションされないようにするための新しいインスタンスへの参照がありますか?これらの質問はもう少しメタです。

0

カレンダーインスタンスからの読み込みだけに興味がある場合は、ガベージコレクタがあまり多くの作業を行う必要がないため、最初にメソッドを少し上回る方が良いでしょう。

0

最初のブロックは、現在の日付と時刻を1回クエリします。おそらく両方で同じタイムスタンプを使用したいと思うので、これは良いことです。

新しいCalendarオブジェクトを初期化する必要があるため、2番目の例は遅くなります。また、2つの異なるタイムスタンプが存在してもよい。最初のメソッドが23:59:59.875の時間で呼び出され、2番目のメソッドが00:00:00.007の時間で呼び出されたときに真夜中頃に何が起こるか自問してください。本当にそれが欲しいですか?

技術的にも厳密にも、最初のコードスニペットでは長い時間メモリが使用されています。しかし、ほとんどすべてのケースで、それでうまくいくはずで、2番目のコードスニペットを参照してください。

ところで、ローカル変数にはメモリがかからないと仮定できます。特に頻繁に使用されるコードでは、最適化されます。

0
  1. 少ないメモリ少ないCPUを使用するガベージコレクタは直ちにそれを参照の最後使用後カレンダーインスタンスを収集して自由であり、より多くのメモリ、よりCPU

を使用します。

関連する問題