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

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

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

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

Q&A

解決済

1回答

5231閲覧

java Stringを宣言した場合の、メモリの確保の仕方

karino_nao

総合スコア18

Java

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

0グッド

1クリップ

投稿2021/10/31 03:07

編集2021/11/16 22:15

java Stgingを宣言した場合の、メモリの確保の仕方について

私の理解の前提

javaで変数宣言時のメモリを確保するイメージは、以下の通りと思っています。

・intを宣言した時、32バイト分のメモリを確保する
・doubleを宣言した時、64バイト分のメモリを確保する
→int、doubleで確保したメモリ以上の値を代入すると、エラーになる

困っている点

が、Stringを宣言した場合、
メモリ上でどのような確保の仕方をするのかがわからず困っています

String a = "hello";
この宣言時、5バイト分?のメモリを確保する、と思ったのですが
その後
a = "add text";
と文字を代入した場合、
新たに8バイト分?のメモリを確保するのか("hello"分の5バイト分は解放される?)
5バイト分に"add t"が入り、新たに3バイト"ext"が確保されるのか(もしくは別?)
というのが、調べてもわかりませんでした(キーワード・検証方法も??で…)

お時間あるときでも
java Stgingを宣言した場合の、メモリの確保の仕方
について、ご教授いただけたらと思います。

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

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

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

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

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

BeatStar

2021/10/31 03:29

Stgingとはなんでしょうか。String? そうなら、ちゃんと書きましょう。 人間同士ならなんとなく判断が付きますが、機械はそんな芸当はできません。 プログラミングは「機械とのコミュニケーション」です。 質問は修正できるので修正しましょう。
dodox86

2021/10/31 03:30 編集

> Stringを宣言した場合、メモリ上でどのような確保の仕方をするのかがわからず困っています プログラミングする上で具体的に困ることが何かあるのでしょうか。Javaは基本的に、そのような意識をしなくてもよいように設計されています。 > →int、doubleで確保したメモリ以上の値を代入すると、エラーになる ここで言うエラーが、コンパイルエラーを指しているのか、実行時のエラーを指しているか分かりませんが、コンパイルエラーであれば、実行時にメモリ確保する以前のお話です。コンパイルエラーがなくなるようにコードを書けば、intやdoubleの変数に代入するときに切り捨てられるだけです。 具体的に何か困っている訳ではなく、好奇心からの質問でしょうか。
jimbe

2021/10/31 03:34 編集

タイトルに誤字があります。 文字のカウント単位はビットではなくバイトです。 int/double はプリミティブ、 String はクラスで、内部表現は全く違います。 java は c でのメモリ確保等の面倒な部分を意識しなくて済むように作られていますので(それが成功しているかはさておき)アプリでメモリ確保を心配する必要はありません。 java仮想マシンレベルのお話であれば、そのような情報に当たってください。
dodox86

2021/10/31 03:34

> 5ビット分...8ビット分 それを言うなら「バイト」です。さらに、Javaプログラムの実行時、内部では1文字を2バイト(UTF-16)で扱っています。
karino_nao

2021/12/05 03:40

回答ありがとうございます。 遅まきながら、バイト、Stringの件は修正しました。 ご指摘ありがとうございました!
guest

回答1

0

ベストアンサー

色々と間違っていますが、細かいところを理解するにはJavaやプログラミング一般についてもっと詳しくならないと難しいです。取りあえず解説を書いてみましたが、以下は、ある程度の知識が無いと理解できないかも知れません。


まず、Javaの変数には大きく分けてプリミティブ型と参照型の二種類があります。この二つはそれぞれをわけて考える必要があります。

プリミティブ型とはintdoubleといった基本的なベースになる型です。この型で変数が宣言された場合、その型のサイズ分のメモリ領域が確保されます(ローカル変数の場合はスタックに積まれ、インスタンス変数の場合はそのインスタンス作成時にヒープに確保されますが、この話はひとまず置いておきます。)。サイズは型によって決まっており、intであれば4バイト、doubleであれば8バイトと言ったようにです。

参照型はint[]のような配列の型またはStringのようなクラスのオブジェクトの型です。この型では変数が宣言された場合、実際のオブジェクトを参照するために必要な分のメモリ領域が確保されます。実際の所では、Cで言えばポインタと呼ばれるもので実装されており、64bitアーキテクチャ向けの実装では8バイトです(以下の文章では、64bitの環境を前提とし、8バイトを確保する物として扱います。)。その変数の中身は、配列またはオブジェクトを指し示す値が入っています。また、nullという特殊な値も入れることができ、どのオブジェクトも指し示さないことを表す値です。

ここで注意して欲しいのは、参照型の変数の中に配列やオブジェクトが入っているわけでは無いことです。変数の中はそれらを参照する値(しばしば参照値と言われます)であって、オブジェクトそのものではないのです。では、配列やオブジェクトはどのタイミングできるのかというと、new演算子を使ったときに、配列ならその時指定されたサイズのメモリ領域が確保され、クラスのオブジェクトならクラスのインスタンス変数全てを確保できる分のメモリ領域が確保されます。サイズが10のintの配列なら4×10=40バイト、intを2つdobuleを1つStringを2つインスタンス変数として持つクラスのオブジェクトなら4×2+8×1+8×2=32バイト、と言う形です。(さらに配列の長さやオブジェクトの情報を管理するための領域が確保されています。)

これを踏まえて

Java

1String a = "hello";

が何をしているのかを考えます。最初にaの為に確保されるメモリはどれぐらいかというと、参照値を入れる分だけであるため8バイトです。では、"hello"はどこに確保されるのでしょうか?この"hello"は文字列リテラルという物で、実際の所はStirngをnewする処理をしています。上のコードは

Java

1char[] data = {'h', 'e', 'l', 'l', 'o'}; 2String a = new String(data)

と同じです(参考)。newでオブジェクトのインスタンス変数分のメモリが確保されるという話でした。では、Stringのオブジェクトのインスタンス右辺数に"hello"の分のメモリが確保されるのかというと、実は違うのです。銅なのかというと、実際のコードを見る方がわかりやすいでしょう。

String.javaのコードはStringの実際の実装です(OpenJDK 17の物ですが)。"hello"のデータがあるのはprivate final byte[] value;と宣言されたインスタンス変数です。このインスタンス変数は参照型であるため、Stringとしては8バイト分しかメモリは用意されません。でも問題ありません。このvalueは、"hello"のデータが保存された配列を示す参照にすぎないから、8バイトで十分なのです。実際の"hello"のデータはここStringUTF16.compress()またはStringUTF16.toBytes()で作成されたものへvalueが指し示すようになります(参照型への代入は指し示す物の変更です)。さらに、StringUTF16.javaをみればわかるように、Latin1に収まるなら文字数の同じバイト数のbyte配列を作成してLatin1として文字が入れ(StringUTF16.compress())、収まらないなら文字数の2倍のバイト数(コードではlen << 1)のbyte配列を作成してUTF16として文字を入れ(StringUTF16.toBytes())、それがvalueに代入される(valueさ指し示す先がそれらのbyte配列になる)と言うことです。"hello"はLatin1に収まるため、5バイトのbyte配列が作成されることになります。

つまり、"hello"という文字が実際に持っているデータというのは、変数a(8バイト)が指し示す先のStringオブジェクトが持つインスタンス変数value(8バイト)が指し示す先のサイズが5のbyte配列にあるということです。

そこから

Java

1a = "add text";

は何をしているのかです。"add text"というのは、これまたnew String(...)としているだけですので、"add text"の入ったbyte配列を指し示すインスタンス変数valueを持つ全く新しいStringオブジェクトになります。これが、aに代入されるのですが、参照型への代入は、参照値を入れ替えることになり、言ってしまえば、参照先の差し替えてです。aが持もつ値というのは、"hello"のデータを持っているStringオブジェクトを指し示す参照値から、"add text"のデータを持っているStringオブジェクトを指し示す参照値に変わると言うことです。

"hello"のデータを持っているStringオブジェクトはどうなるのかというと、どこからも参照されなくなりますので、しばらくしたらガーベージコレクターによって回収され、確保していたメモリは解放されることになります。


より詳しくはJava言語仕様書やJava VM仕様書を読んでください。ただ、一定上のプログラミングやコンピューターの知識がないと、ちょっと理解するのは難しいかと思います。CやC++のような自分でメモリ管理が否が応でも必要な言語なら、これらを理解していないと簡単なプログラムですら作るのは難しいですが、Javaのようなガベージコレクション前提の言語では、メモリ使用量の改善が必要になるなど特殊な状況にならない限り、メモリがどのように確保されるかどうかは、ほとんどの場合で必要とされない知識だと思います。トップレベルのプログラマーになるなら必要ですが、たぶん、CやC++等を触った後で無いと難しいでしょう。配列のメモリ確保の実際の動作とかを調べるにはそれこそC/C++で書かれたネイティブなコードをみないといけなくなりますから。

投稿2021/10/31 08:04

編集2021/10/31 08:08
raccy

総合スコア21739

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

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

karino_nao

2021/12/05 03:40

回答ありがとうございます! 遅まきながらではありますが。 理解として、アドレスをもつ、というところで理解しました。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問