質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

4回答

5904閲覧

Javaのメモリ共有の仕組について

syncrock

総合スコア209

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2015/04/22 01:02

編集2015/04/22 02:06

Javaのメモリ共有の仕組みについて教えてください。
privateなどで宣言されたようなヒープ領域にある変数について、スレッドセーフの仕組になっていない場合はメモリ共有(データの書き換え)などが起こり得ると思いますが。
いったい、どのような仕組なのでしょうか。
クラスAにprivateで宣言したA'というオブジェクトがあった場合、A'はヒープ領域に割り当てられると思います。
その後、他のスレッドでもクラスAでの動作があり、A'がヒープ領域に割り当てられる場合、もちろんアドレスは最初に割り当てられたところとは違う箇所に割り当てられますよね?
それでも、書き換えが起こるということは、Javaのなかでスレッド毎に割り当てたアドレスを管理出来てないのでしょうか?
「えーっと、A'のアドレスどこだっけ。あ、ここにA'のオブジェクトがある、きっとここかな。」みたいな感じで間違え得るのでしょうか。
それとも、アドレスを単に間違えるだけではない理由があるのでしょうか。
もし、参考になるようなネットのサイト等も教えて頂けると助かります。
宜しくお願いします。

回答を受け、少し追記します。
・インスタンスはスレッド毎にできます。
・「private オブジェクト名 変数名;」で宣言した変数がデータの書き換えが起こっています。
・メインメソッドをsynchronizedにするとか、上記変数をローカル変数にするとかすれば治ります。

ただ、なぜインスタンスは別なのに起こるのかと思ってまして。
以前、springを使ったときにscopeをprototypeにしたときは問題なかったと思っており、結局インスタンスは別になるのに何が違うんだろうと。
(ここの解釈自体が間違えているのかもしれませんが。)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

それでも、書き換えが起こるということは、Javaのなかでスレッド毎に割り当てたアドレスを管理出来てないのでしょうか?
「えーっと、A'のアドレスどこだっけ。あ、ここにA'のオブジェクトがある、きっとここかな。」みたいな感じで間違え得るのでしょうか。
それとも、アドレスを単に間違えるだけではない理由があるのでしょうか。

この文面を見た限りでは Java(JVM) が間違って書き換えてしまうと理解されているようですが、そうではありません。プログラマの実装ミスです。

質問に近いケースを考えると
0. Class A のインスタンスを1つ作成。スレッド1,2でこのAのインスタンスを参照する
0. Class A のインスタンスをスレッド1,2でそれぞれ生成。(Aのインスタンスが2つある状態)
となりますが、前者は複数スレッドで1つのインスタンスを共有しているので、スレッドセーフに実装しないと意図しないデータの書き換えが起こる可能性があります。
後者はインスタンスが2つあるので書き換えられることはありません。
質問のお話しはたぶん後者のことですよね?

投稿2015/04/22 01:18

kodai

総合スコア759

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

syncrock

2015/04/22 01:55

そうです、後者です。 スレッド1,2でそれぞれインスタンスを生成しているにも関わらず、データの書き換えがされている事象が起こっております、 もちろん、synchronizedを行ったり、スレッドセーフにする実装を行えば解決はするんですが。 そもそもなぜ、書き換えられることがあるのかなぁと。
kodai

2015/04/22 02:11

うーん、なるほど。ちょっとこれはコード見ないとわからないですね。 データの書き換えが本当に起こっているなら > 「スレッド1,2でそれぞれインスタンスを生成している」 この部分がきちんとできていないと思います。 生成は new でやってますか?それともどこかから取得してますか?
syncrock

2015/04/22 02:31

>うーん、なるほど。ちょっとこれはコード見ないとわからないですね。 コードに関しては申し訳ありません。 >生成は new でやってますか?それともどこかから取得してますか? これに関しては私の知識不足なので「そう聞いている」としか答えれないのですが、 Strutsを使用しており、シングルトンのBaseのものが各アクションのインスタンスをそれぞれ生成している。と考えていました。 そもそも、そこがおかしい(それぞれインスタンスを生成しない)のでしょうか。 Strutsを使用して動いているアクションはそれぞれインスタンスを生成してないのであればそこが原因だと思いますが。。
KoichiSugiyama

2015/04/22 02:36

横からすみません。シングルトンベースだとすると、全てのインスタンスで同じ物が参照されていますよ。シングルトンとはその単一性を保証するものです。
kodai

2015/04/22 02:43

いままでの話を総合するとまず間違いなく同じインスタンスが共有されていますね。 仮に以下のようなコードだとしたら ```lang-java class HogeAction extends BaseAction { private Fuga fuga; ``` 1. HogeAction がシングルトンで fuga がコンストラクタなどで一度しか生成されていない 2. Fuga がシングルトンまたはインスタンスが DI されていて共有されている のケースですかね。 ちなみに Struts は 1 ですか?アクションは1つしか生成されなかったと思うのでフィールド定義したらダメですよ。
syncrock

2015/04/22 03:52

>KoichiSugiyama 回答ありがとうございます。 全てのインスタンスが同じものを参照・・・であれば、毎回データの書き換えが起こると思いますが、そうではないのでしょか。 記載が抜けてましたが、高負荷をかけた場合のみデータ書き換えが起こっており、通常では特にそのような事が起こっていないので。。 kodaiさん 何レスもありがとうございます。 Struts1ですね・・・。 と言うことは、インスタンスは1つしか生成されていない・・・ということでしょうか。 ただ、上記にも書きましたが、普段はデータ書き換えが行われずに高負荷のテストを行った時だけ行われたのですが、アクション1つだけであれば、頻繁に起こる・・・っていうわけではないんですかね?
syncrock

2015/04/22 05:29

立て続けにすいません。 1つのアクションを生成しますが、その生成した1つのアクションでインスタンスを生成した場合。 その生成されたインスタンスは共有されるのでしょうか。
argius

2015/04/22 08:12

横から失礼します。 スレッドセーフでないことによる問題は、再現性が低い場合があるので、まさにご質問の件のように高負荷状態だけで発生することもよくあります。 Struts1のActionのスレッドセーフの扱いについては、キーワード[struts1 thread safe]で検索してみてください。
syncrock

2015/04/22 09:08

>argiusさん 回答ありがとうございます。 通常起こらず、高負荷の時だけ・・・・はありえるのですね。。
kodai

2015/04/22 09:51

argiusさんのコメントにもある通り「高負荷の時だけ」というのはマルチスレッドに起因するバグの典型的な症状ですね。
syncrock

2015/04/22 10:05

>kodaiさん そうなのですね。。。 共有された1つのアクションクラスからスレッド毎にインスタンス生成されたクラスの中でフィールド定義されたもの(ヒープ領域)にされたものは、いくらスレッド別のインスタンスの中とはいえ、書き換えが起こる可能性があるんですね。。。 それが常ではなくて高負荷の時だけですか、、うーん、納得は行きますが納得いかないですね、これ(笑)
syncrock

2015/04/23 00:01

一旦解決とさせていただきます。 色んな状況をもう少し整理します。 ベストアンサーとして、やりとりをさせていただいたこちらの回答を選ばせて頂きます。 また、違う形で質問を作っていたら、その時は宜しくお願いします(笑)
guest

0

お探しのところと合致してるかは分かりませんが、以下のページを見つけました。

意外と教わる機会の少ないメモリ管理のお話
http://www.ibm.com/developerworks/jp/java/library/j-jtp06197.html

投稿2015/04/22 10:11

hpfoon

総合スコア52

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

もしかしたら,Aのインスタンス生成が複数のスレッドから同時に呼び出されたせいで,
その呼び出した複数のスレッドに同じオブジェクトが返っているのではないでしょうか.

そもそもsynchronized修飾子はそういった場合に発生する整合性の問題を解決するために存在します.
読本Java/9.2 ロックとアンロック

例えばCalendar.getInstance()は内部的にはGregorianCalendarの新規インスタンスを生成して返しているだけですが,このメソッドもsynchronizedです.
複数回呼び出されて時刻を操作使用として他の時刻に影響を与えないよう,そうしているのでしょう.

投稿2015/04/22 02:21

swordone

総合スコア20649

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

syncrock

2015/04/22 03:54

回答ありがとうございます。 結果的にすごく稀なタイミングで同じものが返ってしまった可能性がある。 ってことがありえるということですか。。 ちょっと考えたことなかったです、ありがとうございます。
guest

0

もしかしてprivate staticと宣言していませんか?
だとしたら同じクラスの全てのオブジェクトでその変数は唯一の存在になりますので、ご質問の現象が起こる可能性があります。

投稿2015/04/22 01:23

KoichiSugiyama

総合スコア3041

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

syncrock

2015/04/22 01:57

回答ありがとうございます。 いえ、privateですね。(私の知識不足だけで、実は暗黙的にstaticになるよ。とかあればそうなのかもしれませんが。) 単純に「private オブジェクト名 変数名;」で宣言しています。
KoichiSugiyama

2015/04/22 02:33

念のために確認ですが、「クラスAにprivateで宣言したA'というオブジェクト」は内部にstatic宣言されている変数を持つクラスであったりしませんか? ソースを見ることができるのであればオブジェクトA'がどういったものか確認してみてはいかがでしょうか。
syncrock

2015/04/22 07:33

そのオブジェクト内ではstaticで宣言されている変数などはありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問