Flutter technical note

Flutterの話をチョットとメモリ勉強メモ

私のMacBook、AndroidStudioを立ち上げて、シミュレーターたちあげて...でFlutterやると、すごい音だすのです。CPUの音ですかね?HDの音ですかね?放っておくと勝手にリブートがかかります🥶

スペックは

  • Core i5
  • メモリ8G
  • Macintosh HD

なのですが、購入当初はIDEとかそんな入れる予定じゃなかったので、パパにメモリ16Gはあったほうがいいよというアドバイスをきかずに、こんなもんで十分、と思って買ってしまったのですが、今入っているものをみたら、ちょっとみただけで、

  • Xcode
  • GoLand
  • PyCharm
  • AndroidStudio
  • デザイン系(Adobe製品いろいろ)
  • Docker(いろんなイメージがいろいろ)
  • VisualStudio
  • VS Code

ほかにも、重たそうなアプリが数え切れない入っているのでした・・(そしてなんか、スタンバってる子がいるし)

ソサエティコミュニティで、Flutterやってると重いんですーと話したら、エンジニアのみなさん、こんなしょーもない質問に、いろいろ答えてくれて、みんなやさしい😭 。

質問「MacbookProが重たくて(とくにFlutterやっているとき)、次はMacMini買ってみようかなと思っているのですが、みなさんどれくらいのスペックのマシンで開発されいますか?」

  • CPUいちばんいいの買う派
  • SSDは予算ゆるすかぎり大きいの買う派
  • コードはみんなgithubにあげちゃうので、SSDは少なめ派
  • MacMiniなら外付SSDという方法も

などなど、教えていただきました。ほかにも

クラウドで仮想環境立てた方がリーズナブルじゃね?という意見もありますよね

とか(そんなことできるの?😳)

Xcode系のbuildだとクラウドでもmac使う必要あってコストかかりますよね。何をどうビルドするかによりますね。

Xcode系のbuildをクラウドでってどゆこと?? ?????

中島聡さんからもコメントをいただく😳

Flutter も同じだと思いますが、Xcode のパフォーマンスに一番影響があるのは、(CPUスピードでも、SSDの容量でもなくて)メインメモリのサイズです。必要なメモリが不足すると、SSDとの間で頻繁なデータのやりとり(ページング)が必要になるため、極端に遅くなるのです。私の MacBook Pro は購入時(2016年)に最大の 16GB にしました。次に買い換える時(今年の末に Apple チップ内臓の MacBook が出た時)には 32GB にする予定です。開発用には、CPUを最速のものにする必要は全くありません。

ページングって、そういえば、昔LPICの勉強したときにやったなーと、そのときはぼんやりでしたが、

SSDとの間で頻繁なデータのやりとり

なるほど・・数十年のときを経てイメージがつかめたのでした。。。。。。CS知識ゼロすぎてつらい。

Goのコミュニティの人たちもそうですが(あと最近入り浸ってる女性OnlyのPython株価分析の勉強会とか、Flutterのもくもく会とか)、みんな、やさしいし、アホな質問にも塩対応せずわかりやすく教えてくれるしで、もうみんな神様にしか見えません。いい時代だ.......。若い時にこういうのほしかった。

(追記)なんと、ツイートされてる

Flutterから離れますが、メモリ話が続きます。先日SoftwareDesignの特集「データ型を正しく説明できますか?」を読んだのですが、メモリについてわかりやすく書かれていて勉強になりました。先日もヒープとかスタックとかブログに書いた気がしますが、おさらいメモ↓。

メモリ

静的領域

  • グローバル変数やstatic宣言した変数の値が格納される領域
  • プログラムの最初から最後まで存在し続ける

スタック

  • ローカル変数を保持する領域
  • ローカル変数はそのメソッドを抜けるまでしか使用しないので、メソッドを抜けたら、その領域は縮む
  • ローカル変数にスタックを使うことで、現在動いていないメソッドのローカル数分の領域が節約できる
  • 再帰呼び出しも可能

ヒープ

  • Cならmalloc()、JavaやC#ならnewで確保する領域
  • 解放はCならfree()、他の言語はGCが解放する
  • ヒープ内のオブジェクトは任意の順序で不要になるため、いまメモリのどこが使用中で、どこが未使用なのかを処理系が管理しなければならない

GCの処理系が何を持ってメモリの領域(ヒープで確保した領域)を不要と判断するのか

  • 静的領域やスタックから参照が辿れなくなったら不要と判断する

Cは配列や構造体を静的領域やスタックに直接格納可能。
Javaは、配列やクラスのオブジェクトはすべてヒープに格納する。

静的型付け言語(参照型)

int[] a = new int[]{1, 2, 3}
int[] b = a; // ①
b[1] = 10;   // ②
  1. aが持っている参照値をコピー
  2. a[1]も10になる

動的型付け言語

  • どんな値でも格納できる = すべての変数が参照型 と考えることができる
  • 参照型はメモリ上のオブジェクトを指し示す型なので、サイズが一定
  • なのでRubyやPythonにはプリミティブ型とう概念がない
a = 10 # ①
b = a  # ②
a += 1 # ③
  1. immutable(変更不能)になっているため
  2. ここで同じ同じオブジェクトを指していても問題は発生しない。。
  3. a, b は同じ10を指しているけど、インクリメントした時点で、新しく11というオブジェクトが作られ、bは10を指したまま。
  • 毎回新しいオブジェクトが作られちゃうと、すぐにヒープがいっぱいになってしまう(GC大忙し)
  • 実際はすべてヒープに確保されるわけじゃない
  • 使用頻度の高い型は、変数の中に値を保持していたりする

複合型

静的型付け言語。Cは値型。それ自体にnameとageを含む。Cの構造体の場合↓

typedef struct {
 	char name[32];
 	int age;
} Person;

Person p; // ①
strcpy(p.name, "hanako"); // ②
p.age = 24;               // ②
  1. 宣言したらメモリにデータを入れる領域ができるので
  2. すぐに使えちゃう!

静的型付け言語。Javaは参照型。参照だけもつ。Javaのクラス↓

class Person {
 	String name;
 	int age;
}

Person p; // ①
p = new Person(); // ②
p.name = "花ちゃん"
p.age = 21;
  1. 入っているのはデータを入れる領域への参照値なので、宣言してもすぐ使えない
  2. 「new Person()」でデータを入れるメモリ領域を確保し、「p =」でpをそこに向ける

動的型付け言語。参照型。参照値しかもたない。

class Oyatsu
 	attr_reader: snacks, :cnt
 	def initialize(snacks, quantity) // ②
 	  @snacks = snacks
 	  @cnt = cnt
  end
end

hoge = 1
hoge = "あらいぐまラスカル"
hoge = Oyatsu.new("飴ちゃん", 10) // ①
  1. hoge = Oyatsu.new("飴ちゃん", 10)で、Oyatsu.newでインスタンスを生成
  2. initializeでsnacksとcntに代入した時点でフィールドが作成される(メモリが確保される)

条件分岐でsnacksに値がはいり、cntに値がはいらないとき、snacksはメモリ上に存在し、cntは存在しないとうオブジェクトができる。

Ruby、PythonとかJavaScriptといった言語は「プリミティブ型」「参照型」を区別する必要なない(区別がないとういわけではない)。すべてを参照型として扱える。

プリミティブ型は、このサイト がわかりやすい。

最近のJavaやC#は auto boxingとかいう機能で、 Object obj = 1; とか書けちゃうらしい(似たようなことを前日参加したGoの輪読会で訳者の柴田さんもいってました)

-Flutter, technical note